Міністерство освіти і науки молоді та спорту України
Національний університет „Львівська політехніка”
Кафедра ЕОМ
КУРСОВА РОБОТА
з дисципліни:
«Паралельні та розподілені обчислення»
на тему:
«Паралельне виконання операцій множення матриць»
Варіант № 20
Завдання до роботи
Розробити схему та описати процедуру перемноження матриці А (розмірністю n1*n2) на матрицю В (розмірністю n2*n3) на структурі з восьми процесорів. Для цієї структури визначити час виконання алгоритму, відсоток послідовної частини алгоритму та ефективність алгоритму.
n1=2Б, n2=4П, n3=2І – КІ-44
де nП, nБ та nІ номер букви в прізвищі, імені та по-батькові відповідно.
Шимків Василь Романович
n1=2Б – О = 240 n2=4П – К = 208 n3=2І – А = 117
Таблиця 1. Дані для завдання
№ Вар.
Розміри матриць
Тип початкового завантаження даних
N1
N2
N3
20
240
208
117
3*
Тут використано наступні позначення:
3*- завантаження початкових даних в процесори з розподіленою пам’яттю.
Співвідношення часових параметрів:
tU = 10tS =6tP =4tZ =4tW
tU - час виконання однієї операції множення;
tS - час виконання однієї операції сумування;
tP - час виконання однієї операції пересилання даних між процесорами;
tZ - час виконання операції завантаження одних даних;
tW - час виконання операції вивантаження одних даних.
А(240*208) та матрицю В(208*117)
Розробити та описати алгоритм множення матриць А*В на структурі яка задається виразом:
3b-6b-2b-5b-10b-13b-14b-11b – КІ-44
Таблиця 2. Декодування структури множення
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Ш
И
М
К
І
В
В
А
С
И
Л
Ь
Р
О
М
А
Н
О
В
И
Ч
3
1
4
2
5
8
6
7
Отримали: МВИІИРОЛ
Отримання матриці зв’язків орієнтованого графа:
43 - 00101011 0 0 1 0 1 0 1 1
203 – 11001011 1 0 0 0 1 0 1 1
91 - 01011011 0 1 0 1 1 0 1 1
223 – 11011111 => 1 1 0 0 1 1 1 1
91 - 01011011 0 1 0 1 0 0 1 1
93 - 01011101 0 1 0 1 1 0 0 1
250 – 11111010 1 1 1 1 1 0 0 0
212 – 11010100 1 1 0 1 0 1 0 0
Анотація
В даній курсовій роботі проведено розробку програмної реалізації восьми процесорної паралельної системи зі спільною пам’яттю, яка виконує множення двох матриць розмірами 240х208 та 208х117. Також наводяться числові значення характеристик даної системи таких як ефективність, коефіцієнт відношення часу виконання паралельної частини програми і часу виконання всієї програми. Проведено також порівняння даного алгоритму з простим послідовним за такими основним ознаками, як час виконання однакової задачі на різних алгоритмах, ефективність.
Алгоритм виконання множення 2-ох матриць реалізований на С++ з консольним інтерфейсом, та з використанням MPI.
Annotation
In this course work developed program of eight parallel processor system with shared memory, which performs multiplication with dimensions 240x208 and 208x117. There are numerical values of the characteristics of the system such as efficiency, the ratio of the execution time of the parallel program and the execution time of parallel applications and runtime. Comparing this algorithm with a simple serial to such basic functions as performing the same task on different performance algorithms. Multiplication algorithm of two matrices implemented in C + + with a console interface, and using MPI.
Зміст
Вступ……………………………………………………………………………..5
Теоретичний розділ…...………..………………………………………..8
Проектування граф-схеми виконання алгоритму …..……………....12
Розробка функціональної схеми...………………………..…………...16
Розрахунковий розділ…………………..…………………………….. .19
Розробка програми……………………………………………………...21
Результат роботи програми……………………………………………23
Висновки…………………………………...…………………………………...25
Література……………………………………………...………………………26
Додаток. Лістинг програми……………………………………………...……27
Вступ
Ідея розпаралелювання обчислень базується на тому, що більшість задач може бути розділена на набір менших завдань, які можуть бути вирішені одночасно. Паралельні обчислення використовувалися багато років в основному в найпродуктивніших обчисленнях, але останнім часом до них зріс інтерес внаслідок існування фізичних обмежень на зростання тактової частоти процесорів.
Поява в останні роки великої кількості порівняно дешевих кластерних паралельних обчислювальних систем призвело до швидкого розвитку паралельних обчислювальних технологій, у тому числі і в області високопродуктивних обчислень. Останнім часом ситуація в галузі паралельних обчислювальних технологій почала кардинально змінюватися в зв'язку з тим, що більшість основних виробників мікропроцесорів стали переходити на багатоядерні архітектури. Зміна апаратної бази змушує змінювати і підхід до побудови паралельних алгоритмів. Для реалізації обчислювальних можливостей багатоядерних архітектур потрібна розробка нових паралельних алгоритмів. Ефективність використання обчислювальних ресурсів, яку будуть мати кластери нового покоління, напряму залежатиме від якості власне паралельних програм, так і спеціалізованих бібліотек чисельних алгоритмів, орієнтованих на багатоядерні архітектури.
1.Теоретичний розділ
Основна ідея розпаралелювання обчислень – мінімізація часу виконання задачі за рахунок розподілу навантаження між декількома обчислювальними пристроями. Цими «обчислювальними пристроями» можуть бути як процесори одного суперкомп'ютера, так і кілька комп'ютерів, обєднаних за допомогою комунікаційної мережі в єдину обчислювальну структуру – кластер.
Паралельна модель програмування сильно відрізняється від звичайної – послідовної. Існують дві моделі паралельного програмування: модель паралелізму даних і модель паралелізму задач. Модель паралелізму даних має на увазі незалежну обробку даних кожним процесом (наприклад, векторні операції з масивами). Модель паралелізаму задач передбачає розбиття основної задачі на самостійні підзадачі, кожна з яких виконується окремо й обмінюється даними з іншими. Це більш трудомісткий, у порівнянні з паралелізмом даних, підхід. Перевагою є велика гнучкість і велика воля, надана програмісту в розробці програми, що ефективно використовує ресурси паралельної системи. При цьому можуть застосовуватися спеціалізовані бібліотеки, що беруть на себе всі «організаційні» задачі. Приклади таких бібліотек: MPI (Message Passing Interface) і PVM (Parallel Virtual Machine).
При множенні матриць А(mxn) і В(nxl) отримаємо матрицю С(), кожен елемент якої визначається відповідно до виразу:
/ (1)
Як випливає з (1), кожен елемент результуючої матриці С є скалярний добуток відповідних рядка матриці A та стовпця матриці B:Цей алгоритм передбачає виконання mxnxl операцій множення і mx(2n-1)xl операцій додавання елементів вихідних матриць.
Послідовний алгоритм множення матриць видається трьома вкладеними циклами:Алгоритм 1.Послідовний алгоритм множення двох квадратних матрицьfor (i = 0; i <n; i + +) { for (j = 0; j <l; j + +) { MatrixC [i] [j] = 0; for (k = 0; k <m; k + +) { MatrixC [i] [j] = MatrixC [i] [j] + MatrixA [i] [k] * MatrixB [k] [j]; } }}
Цей алгоритм є ітеративним і орієнтований на послідовне обчислення рядків матриці С. Дійсно, при виконанні однієї ітерації зовнішнього циклу (циклу за змінною i) обчислюється один рядок результуючої матриці (Рис. 1.1).
/Рис. 1.1.
На першій ітерації циклу за змінною i використовується перший рядок матриці A і всі стовпці матриці B для того, щоб обчислити елементи першого рядка результуючої матриці С.
Оскільки кожен елемент результуючої матриці є скалярний добуток рядка та стовпця вихідних матриць, то для обчислення всіх елементів матриці з розміром nxl необхідно виконати n*(2n-1)*l скалярних операцій .
З визначення операції матричного множення випливає, що обчислення усіх елементів матриці С може бути виконано незалежно один від одного. Як результат, можливий підхід для організації паралельних обчислень полягає у використанні в якості базової підзадачі процедури визначення одного елемента результуючої матриці С. Для проведення всіх необхідних обчислень кожна підзадача повинна містити по одному рядку матриці А і одному стовпцю матриці В.
Для обчислення одного рядка матриці С необхідно, щоб у кожній підзадачі містилася рядок матриці А і був забезпечений доступ до всіх стовпцях матриці B. Можливі способи організації паралельних обчислень полягають у наступному.Алгоритм являє собою ітераційну процедуру, кількість ітерацій якої збігається з числом підзадач. На кожній ітерації алгоритму кожна підзадача містить по одному рядку матриці А і одному стовпцю матриці В. При виконанні ітерації проводиться скалярне множення, що призводить до отримання відповідних елементів результуючої матриці С. Після завершення обчислень в кінці кожної ітерації стовпці матриці В повинні бути передані між підзадачами з тим, щоб у кожній підзадачі виявилися нові стовпці матриці В і могли бути обчислені нові елементи матриці C. При цьому дана передача стовпців між підзадачами повинна бути організована таким чином, щоб після завершення ітерацій алгоритму в кожній підзадачі послідовно опинилися всі стовпці матриці В.Можлива проста схема організації необхідної послідовності передач стовпців матриці В між підзадачами полягає в представленні топології інформаційних зв'язків підзадач у вигляді кільцевої структури. У цьому випадку на кожній ітерації підзадача i, 0 <= i <n, буде передавати свій стовпець матриці В підзадачі з номером i +1 - Рис. 1.2. Після виконання всіх ітерацій алгоритму необхідна умова буде забезпечена в кожній підзадачі почерзі опиняться всі стовпці матриці В.
На рис. 1.2 представлені ітерації алгоритму матричного множення для випадку, коли матриці складаються з чотирьох рядків і чотирьох стовпців. На початку обчислень в кожній підзадачі i, 0 <= i <n, розташовуються i-й рядок матриці A і i-й стовпець матриці B. В результаті їх перемножування підзадача отримує елемент Сіi результуючої матриці С. Далі підзадачі здійснюють обмін стовпцями, в ході якого кожна підзадача передає свій стовпець матриці B наступної підзадачі відповідно до кільцевої структури інформаційної взаємодії. Далі виконання описаних дій повторюється до завершення всіх ітерацій паралельного алгоритму.
/Рис. 1.2. Загальна схема передачі даних для паралельного алгоритму матричного множення при стрічковій схемі розділення даних.
Проектування граф-схеми виконання алгоритму
Згідно з заданим варіантом будуємо структуру зв’язків між процесорами. Зв'язок між процесорами ми зобразили у вигляді графа з 8-ма вершинами.
/
Рис.2.1 Граф-схема зв’язків процесорів для множення двох матриць.
Зробивши аналіз графа я прийшов до висновку що дане завдання можна розв’язати організувавши кільцеву структуру звязків між процесорами. Побачити її можна на Рис.2.2.
/
Рис2.2 Граф-схема кільцевого зв’язку між процесорами
Завантаження даних в процесори відбуваються через розподілену пам’ять (рис 2.3).
/
Рис. 2.3. Граф-схема завантаження даних на процесори
Результат множення матриць А та В будемо зберігати в пам’яті 0-го процесора.
Визначемо розмірності підматриць А та В для кожного з процесорів. Для цього ми ділимо кількість рядків матриці А на кількість процесорів(в даному випадку 8) та кількість стовпців матриці В на кількість процесорів. Якщо під час виконання розподілу, не вдається отримати однакову розмірність підматриць, то розділяємо їх таким чином, щоб різниця між ними не була більша за 1.
/
Рис. 2.4 Розбиття на під матриці
Кожен процесор має свою пам'ять. На початку роботи туди буде завантажено для кожного і-го процесора під матриці Аі та Ві. Після перемноження під матриць відбудеться обмін Ві під матрицями по кільці, структура якого була показана вище. Після обміну знову відбудеться перемноження підматриць. Обмін відбуватиметься доти, доки кожен і-тий процесор не виконає множення Аі*В. Після виконання перемножень буде відбуватись збір результату в 1-ий процесор.
На рис. 2.5. наведена граф-схема виконання алгоритму множення двох матриць з розподіленою пам’яттю в загальному випадку.
Рис. 2.5. Граф-схема виконання алгоритму множення двох матриць з розподіленою пам’яттю.
3.Розробка функціональної схеми
/
Рис. 3.1. Функціональна схема роботи процесорів
Операція обміну підматрицями Ві.буде відбуватися паралкльно. Також паралельнобуде виконуватися операція звертання до памяті(оскільки в нас розподілена пам’ять) і операція перемноження.
Відповідно до цього по заверщенні перемножень на кожному з процесорів буде підматриця Сі = А*Ві. Дана схема максммально показує розпаралелення виконання перемноження матриць на 8-ми процесорах.
Також перевагою цього методу є те що даний алгоритм є маштабованим. Наприклад , якщо даний алгоритм процедури множення двох матриць розмножити до множення трьох матриць і більше. Оскільки, часткові результати множення матриь А та В будуть з’являтися ще задовго до повного завершення множення, їх можна буде використовувати для наступних операцій.
Кожен процесор виконує моження підматриць і зберігає проміжні дані, а також обмінюється підматрицею В з сусідім процесором по кільцевій структурі. Пересилання підматриці відбувається по колу між сусідніми процесорами, причому операція відсилання і прийому даних буде виконуватись паралельно. Процесори в цьому випадку завантажені найбільш рівномірно.
Таблиця 1. Опис елементів функціональної схеми
Елемент
Значення
Операція зчитування підматриць з пам’яті.
Позначає операцію перемноження підматриць на процесорах
Цей елемент позначає процедуру пересилки і прийому між процесорами. В2(2) означає що процесор, в якому знаходиться даний блок прийме під матрицю В2 від 2-го процесора. В1->8 означає що даний процесор пересилає підматрицю В1 на 8-ий процесор.
Пересилка підматриці результату на вказаний процесар, в даному випадку – це пересилка підматриці С3 на другий процесор
Запис в пам’ять процесора вказаних підматриць результуючої матриці
4. Розрахунковий розділ
Дані обрахунки ведуться для процесорів з розподіленою пам’яттю.
А(240*208) В(208*117)
A1=A2=…=A8=(30x208) B1=B2=B3=(208x14)
B4=B5=B6=B7=B8=(208x15)
Оскільки пам’ять розподілена, то це означає що завантаження буде відбуватися паралельно, а отже за час завантаження ми беремо час завантаження процесора, який виконує завантаження підматриць з більшим розміром:
TZ = (30 * 208 + 208 * 15) * tZ = 9360 * tZ
Операція пересилання також буде виконуватися паралельно, а отже, обраховуємо пересилку найбільшої підматриці Ві також враховуємо, що пересилка буде відбуватися в 7 тактів:
TP = 7 * 208 * 15 * tP = 21840 * tP = 14560 * tZ
Операція множення також буде виконуватися паралельно на процесорах і займе 8 тактів:
TU = 8 * 30 * 208 * 15 * tU = 748800 * tU = 2995200 * tZ
Час додавання також виконується паралельно:
TS = 8 * 30 * (208 - 1) * 15 * tS = 745200 * tS = 298080* tZ
Збір результату, на кожному етапі операції що описані нище виконуються паралельно, тому для отримання часу збору результату вибираємо більший час:
1-ий етап:
TW = 30 * 117 * tw = 3510 * tw = 3510 * tZ
TP= 30 * 117 * 4 * tP = 14040 * tP = 9360 * tZ
2-ий етап:
TW = 30 * 117 * 4 * tw = 14040 * tw
TP = 30 * 117 * 3 * tP = 10530 * tP = 7020 * tZ
3-ій етап:
TW = 30 * 117 * 3 * tw = 10530* tZ
TW = 9360 + 14040 + 10530 = 33930 * tZ
Загальний час:
Tпар= 9360 + 14560 + 2995200 + 298080 + 33930 = 3351130 * Z
Для порівняння обчислимо умовний час виконання послідовного алгоритму:
TZпос = n1 * n2 + n2 * n3 = 74256 * tZ
Пересилань не буде, тому TPпос =0.
TUпос = 5840640 * tu = 23362560 * tZ
TSпос = 5812560 * tS = 2325024 * tZ
TWпос = 240 * 117 * tW = 28080 * tZ
TПОС = TZпос + TSпос + TWпос = 74256 + 23362560 + 2325024 + 28080 = =25789920 * tZ
Ефективність: E= TПОС / (8Tпар)= 25789920 / (8 * 3351130) = 0,96
Розробка програми
Граф-схема програми наведена на рис. 5.1. Лістинг програми наведений в додатку А. Дана програма містить консольний інтерфейс, розроблена за допомогою мови програмування С++.
Рис. 5.1. Граф-схема алгоритму перемноження матриць на заданій структурі.
Завдяки тому, що при написанні коду програми були використані засоби технології MPI, дана програма не просто імітує роботу паралельноїсистеми, а дійсно є цілком працездатною і може бути запущеною на паралельній системі, яка досліджується у цій курсовій роботі.
Для тестування достовірності результатів паралельної програми, я розробив ще й послідовну, де множаться ці ж матриці.
Для обміну інформацією між процесами використовуються функції бібліотеки MPI 2.0 MPI_Send() та MPI_Recv(). Це парні функції, які призначені відповідно для відправки та прийому повідомлень.
int MPI_Send(void *buf, int count, MPI_Datatype type, int dest, int tag, MPI_Commcomm)
buf - адреса буфера пам'яті, в якому розташовуються дані повідомлення, що відправляється;
count - кількість елементів даних в повідомленні;
type - тип елементів даних повідомлення, що пересилається;
dest - ранг процесу, якому відправляється повідомлення;
tag - значення-тег, що використовується для ідентифікації повідомлення;
comm - комунікатор, в рамках якого виконується передача даних.
int MPI_Recv(void *buf, int count, MPI_Datatype type, int source,
int tag, MPI_Comm comm, MPI_Status *status), де
buf, count, type - буфер пам'яті для прийому повідомлення, призначення кожного окремого параметра відповідає опису в MPI_Send.
source - ранг процесу, від якого повинен бути виконаний прийом повідомлення.
tag - тег повідомлення, яке повинне бути прийняте для процесу.
comm - комунікатор, в рамках якого виконується передача даних.
status - вказівник на структуру даних з інформацією про результат виконання операції прийому даних.
Результат роботи програми
/
Рис. 6.1. Генерація матриці А
/
Рис. 6.2. Генерація матриці В
/
Р ис. 6.3. Результат виконання множення
Висновок
Під час виконання курсового проекту я оволодів технологією написання програм для багатопроцесорних систем. Розробив восьми процесорну систему зі спільною пам’яттю множення двох матриць. Також було проведено деякі обчислення, які дають уявлення про характеристики даного паралельного алгоритму, та порівняно його з послідовним. В результаті проведеної роботи можна зробити такі висновки: для восьми процесорної системи та матриць з розмірами 240х208 208х117 умовний час виконання програми в інтервалах виконання операції виявився рівним 3234868 tZ, а для послідовної структури 8239920 tZ . Ефективність при цьому рівна E = 96% , що є досить хорошим показником.
СПИСОК ЛІТЕРАТУРИ
Корнеев В.В. Параллельные вычислительные системы. М.: Нолидж, 1999
С. Немнюгин, О.Стесик Параллельное программирование для многопроцессорных вычислительных систем. – СПб: БХВ-Петербург, 2002.
Воеводин В.В., Воеводин Вл.В. Параллельные вычисления. – СПб: БХВ-Петербург, 2002.
Ортега Дж. Введение в параллельные и векторные методы решения линейных систем. М.:Мир, 1991.
Программирование на параллельных вычислительных системах: Пер с англ./Под ред. Р.Бэбба.М.:Мир, 1991.
Бройнль Т. Паралельне програмування: Початковий курс: Навчальний посібник. – К.:Вища школа.,1997.
Воеводин В.В. Математические основы параллельных вычислений.- М.: Изд-во МГУ, 1991.
Векторизация программ: теория, методы, реализация: Пер. с англ. и нем. /Под ред. Г.Д.Чинина. - М:. Мир, 1991.
Організація паралельних обчислень : Навчальний посібник з дисципліни “Паралельні та розподілені обчислення” для студентів базового напрямку 6.0915 "Комп'ютерна інженерія" / Укладачі: Є. Ваврук, О. Лашко – Львів: Національний університет “Львівська політехніка”, 2007, 70 с.
http://www.parallel.ru – Інформаційно-аналітичний центр з паралельних обчислень.
http://www.csa.ru – Інститут високопродуктивних обчислень і баз даних.
http://www.hpc.nw.ru – Високопродуктивні обчислення.
Додаток А
Текст програми на C++ з використанням бібліотеки МРІ:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <iostream>
#include "mpi.h"
#include <Windows.h>
using namespace std;
const int route=0;
const int circle[] = {0,7,3,5,4,6,2,1};
const int procNumber=8;
const int N1=240;
const int N2=208;
const int N3=117;
int procRank;
const int root=0;
MPI_Status Status;
struct A{
int row;
int n1;
int n2;
double arr[N1/8+N1][N2];
};
struct B{
int col;
int n2;
int n3;
double arr[N2][N3/8+N3];
};
struct R{
int n1;
int n3;
double arr[N1/8+N1][N3];
};
double matrixA[N1][N2]={0};
double matrixB[N2][N3]={0};
double Res[N1][N3]={0};
A subA[procNumber];
B subB[procNumber];
A procA;
B procB;
B procBtmp;
R procRes;
R result[procNumber];
int NextProc;
int PrevProc;
int procSize;
//Збір
void DataReplication(){
if(procRank==7||procRank==6||procRank==1||procRank==3){
MPI_Send(&procRes,sizeof(procRes),MPI_BYTE,root,0,MPI_COMM_WORLD);
if(procRank==1){
MPI_Recv(&procRes,sizeof(procRes),MPI_BYTE,2,0,MPI_COMM_WORLD,&Status);
MPI_Send(&procRes,sizeof(procRes),MPI_BYTE,root,0,MPI_COMM_WORLD);
}
if(procRank==7){
MPI_Recv(&procRes,sizeof(procRes),MPI_BYTE,5,0,MPI_COMM_WORLD,&Status);
MPI_Send(&procRes,sizeof(procRes),MPI_BYTE,root,0,MPI_COMM_WORLD);
}
if(procRank==3){
MPI_Recv(&procRes,sizeof(procRes),MPI_BYTE,4,0,MPI_COMM_WORLD,&Status);
MPI_Send(&procRes,sizeof(procRes),MPI_BYTE,root,0,MPI_COMM_WORLD);
}
}
if(procRank==4)MPI_Send(&procRes,sizeof(procRes),MPI_BYTE,3,0,MPI_COMM_WORLD);
if(procRank==2)MPI_Send(&procRes,sizeof(procRes),MPI_BYTE,1,0,MPI_COMM_WORLD);
if(procRank==5)MPI_Send(&procRes,sizeof(procRes),MPI_BYTE,7,0,MPI_COMM_WORLD);
if(procRank==root){
result[root]=procRes;
MPI_Recv(&result[7],sizeof(procRes),MPI_BYTE,7,0,MPI_COMM_WORLD,&Status);
MPI_Recv(&result[6],sizeof(procRes),MPI_BYTE,6,0,MPI_COMM_WORLD,&Status);
MPI_Recv(&result[1],sizeof(procRes),MPI_BYTE,1,0,MPI_COMM_WORLD,&Status);
MPI_Recv(&result[3],sizeof(procRes),MPI_BYTE,3,0,MPI_COMM_WORLD,&Status);
MPI_Recv(&result[5],sizeof(procRes),MPI_BYTE,7,0,MPI_COMM_WORLD,&Status);
MPI_Recv(&result[4],sizeof(procRes),MPI_BYTE,3,0,MPI_COMM_WORLD,&Status);
MPI_Recv(&result[2],sizeof(procRes),MPI_BYTE,1,0,MPI_COMM_WORLD,&Status);
}
}
//початкова розсилка
void DataDistribution(){
if(procRank==root){
procA = subA[root];
procB = subB[root];
for(int i=0;i<procNumber;i++)
if(i!=root){
MPI_Send(&subA[circle[i]],sizeof(subA[circle[i]]),MPI_BYTE,circle[i],0,MPI_COMM_WORLD);
MPI_Send(&subB[circle[i]],sizeof(subB[circle[i]]),MPI_BYTE,circle[i],0,MPI_COMM_WORLD);
}
}
MPI_Status Status;
if(procRank!=root){
MPI_Recv(&procA,sizeof(procA),MPI_BYTE,root,0,MPI_COMM_WORLD,&Status);
MPI_Recv(&procB,sizeof(procB),MPI_BYTE,root,0,MPI_COMM_WORLD,&Status);
}
}
//пересилка підматриці і перемноження
void mull(){
for(int i=0;i<procA.n1;i++)
for(int j=0;j<procB.n3;j++)
for(int k=0;k<procA.n2;k++)
procRes.arr[i][j+procB.col]+=procA.arr[i][k]*procB.arr[k][j];
}
void DataSend(){
procRes.n1=procA.n1;
procRes.n3=N3;
//mull();
for(int k=0;k<procNumber;k++){
for(int i=0;i<procNumber;i++){
if(procRank==circle[i]){
if( i % 2==0 ) {
MPI_Send(&procB,sizeof(B),MPI_BYTE,circle[(i+1)%procSize],0,MPI_COMM_WORLD);
MPI_Recv(&procBtmp,sizeof(B),MPI_BYTE,circle[(i+procSize-1)%procSize],0,MPI_COMM_WORLD,&Status);
procB=procBtmp;
} else {
MPI_Recv(&procBtmp,sizeof(B),MPI_BYTE,circle[(i-1)%procSize],0,MPI_COMM_WORLD,&Status);
MPI_Send(&procB,sizeof(B),MPI_BYTE,circle[(i+1)%procSize],0,MPI_COMM_WORLD);
procB=procBtmp;
}
}
}
mull();
}
}
void SetRank()
{
if(procRank==0)
{
NextProc = 7;
PrevProc = 1;
}
if(procRank==1)
{
NextProc = 0;
PrevProc = 2;
}
if(procRank==2)
{
NextProc = 1;
PrevProc = 6;
}
if(procRank==3)
{
NextProc = 5;
PrevProc = 7;
}
if(procRank==4)
{
NextProc = 6;
PrevProc = 5;
}
if(procRank==5)
{
NextProc = 4;
PrevProc = 3;
}
if(procRank==6)
{
NextProc = 2;
PrevProc = 4;
}
if(procRank==7)
{
NextProc = 3;
PrevProc = 0;
}
}
int main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD,&procRank);
MPI_Comm_size(MPI_COMM_WORLD,&procSize);
if(procSize!=8){
cout<<"Must be 8 process"<<endl;
MPI_Finalize();
return 1;
}
if(procRank==root){
//заповнення А
for(int i=0;i<N1;i++)
for(int j=0;j<N2;j++)
matrixA[i][j]=rand()%9+1;
cout<<"Matrix A"<<endl;
for(int i=0;i<N1;i++){
for(int j=0;j<N2;j++)
cout<<matrixA[i][j]<<" ";
cout<<endl;
}
//заповнення В
for(int i=0;i<N2;i++)
for(int j=0;j<N3;j++)
matrixB[i][j]=rand()%9+1;
cout<<endl<<"Matrix B"<<endl;
for(int i=0;i<N2;i++){
for(int j=0;j<N3;j++)
cout<<matrixB[i][j]<<" ";
cout<<endl;
}
//перемноження матриць
for(int i=0;i<N1;i++)
for(int j=0;j<N3;j++)
for(int k=0;k<N2;k++)
Res[i][j]+=matrixA[i][k]*matrixB[k][j];
cout<<endl<<"Result"<<endl;
for(int i=0;i<N1;i++){
for(int j=0;j<N3;j++)
cout<<Res[i][j]<<" ";
cout<<endl;
}
//розбиття на підматриці
//А
int rowsSum=0;
int restRows = N1;
int restProc = procNumber;
for(int i=