Паралельне виконання операцій множення матриць на кільцевій структурі

Інформація про навчальний заклад

ВУЗ:
Національний університет Львівська політехніка
Інститут:
Не вказано
Факультет:
КН
Кафедра:
Кафедра ЕОМ

Інформація про роботу

Рік:
2011
Тип роботи:
Курсова робота
Предмет:
Паралельні та розподілені обчислення

Частина тексту файла (без зображень, графіків і формул):

МІНІСТЕРСТВО ОСВІТИ І НАУКИ, МОЛОДІ ТА СПОРТУ УКРАЇНИ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА” Кафедра ЕОМ  КУРСОВА РОБОТА з дисципліни: “Паралельні та розподілені обчислення” на тему: “Паралельне виконання операцій множення матриць на кільцевій структурі” Варіант № 1 Львів – 2011 ЗМІСТ Вступ 5  1. Теоретичний розділ 6  2. Проектування граф-схеми виконання алгоритму 10  3. Розробка функціональної схеми 12  4. Розрахунковий розділ 13  5. Розробка програми 17  Висновки 19  Література   Додаток. Лістинг програми   Результати роботи програми    ВСТУП На сьогоднішній день найбільш перспективні дві основні технології, які мають багато спільного: паралельні та розподілені обчислення. У паралельних обчисленнях бере участь обладнання, що знаходиться, як правило, в одному фізичному місці, вони тісно поєднані між собою і всі параметри їх роботи відомі програмісту. У розподілених обчисленнях немає тісного постійного зв'язку між вузлами, вони розподілені по деякій території і параметри роботи цієї системи динамічні і не завжди відомі. Існують різні методи і технології паралельних і розподілених обчислень, постійне зростання використання яких в сучасній практичній діяльності можна пояснити наступними обставинами: • надзвичайно швидке зростання складності об'єктів моделювання (перехід від простих до складних ("великим") системам); • перехід до вирішення завдань, вирішення яких вимагає досліджень, які необхідні для проведення ретельного аналізу складної поведінки ; • необхідність управління складними промисловими і технологічними завданнями в режимі реального часу і в умовах невизначеності; • зростання кількості завдань, для вирішення яких необхідно обробляти гігантські обсяги інформації. Домінуюче положення при розробці паралельних програм для паралельних систем займає стандарт MPI (англ. Message Passing Interface). Програма, розроблена в моделі передачі повідомлень, може бути представлена інформаційним графом, вершинам якого відповідають паралельні гілки програми, а ребрам комунікаційні зв'язки між ними. Це можна використовувати для диспетчеризації завдань та їх обчислювальних потоків. Враховуючи гетерогенність обчислювальних ресурсів і середовищ передачі даних у кластері, можна здійснити розподіл обчислювальних потоків (гілок) з обчислювальних вузлів так, щоб мінімізувати накладні витрати на обмін даними між потоками і вирівняти обчислювальне навантаження між вузлами. 1. ТЕОРЕТИЧНИЙ РОЗДІЛ Завдання множення матриць є базовою макрооперацією для багатьох задач лінійної алгебри. Тому ефективний паралельний алгоритм множення матриць дозволяє значно збільшити розмірність подібних завдань без збільшення часу їх вирішення. Нехай дано дві матриці, і., результат яких необхідно обчислити. Елементи результуючої матриці  визначаються за формулою  Час виконання послідовного алгоритму визначається так. Нехай  - час, що витрачається на множення двох чисел,  - час додавання двох чисел. Час, що витрачається на обчислення одного елемента результуючої матриці. В результуючій матриці міститься  елементи, тому загальний час виконання множення матриць буде рівний:  Позначимо . Звідси випливає, що. . Розглянемо паралельний алгоритм множення матриць і оцінимо час його роботи. Нехай є  процесорів, причому, , де  - ціле. Розпаралелимо обчислення так, щоб кожен процесор обчислював елементів результуючої матриці. Тоді сумарний час виконання можна оцінити таким чином:  Позначимо . Порівнюючи  і  , отримаємо : . Маємо, що час, який витрачається на множення матриць за допомогою паралельного алгоритму, в  раз менший, ніж при використанні послідовного. Розглянемо один із способів розпаралелювання алгоритму. Пронумеруємо елементи результуючої матриці за наступним правилом (нумерація елементів, а також рядків і стовпців в даному випадку ведеться з нуля):  Обчислення розподілимо так, щоб перший процесор обчислював перших  елементів результуючої матриці, другий – наступні  й т.д. Таким чином, кінцева і ліва вихідна матриці виходять розподіленими горизонтальними смугами, а права вихідна матриця - вертикальними смугами. Алгоритм перемноження матриці на матрицю на кільцевій структурі Задано дві вихідні матриці A і B. Обчислюється добуток , де А - матриця , B - матриця . Матриця результатів C має розмір . Вихідні матриці попередньо розрізані на смуги, смуги записані в пам'ять. Матриця результатів повертається в нульовий процес. Реалізація алгоритму виконується на кільці з  процесорів. Матриці розрізані як наведено на рис. 1.1: матриця А розрізана на  горизонтальних смуг, матриця B розрізана на  вертикальних смуг, і матриця результату C розрізана на  смуги. Передбачається, що в пам'ять кожного процесора завантажується і може зберігатися тільки одна смуга матриці А і одна смуга матриці B.  Рис. 1.1. Схема розбиття матриць на смуги. Оскільки за умовою в процесорах знаходиться по одній смузі матриць, то смуги матриці B (або смуги матриці A) необхідно "прокрутити" по кільцю процесорів повз смуги матриці A (матриці B). Кожний зсув смуг уздовж кільця і відповідна операція множення наведена на рис. 1.2 у виді окремого кроку. На кожному з таких кроків обчислюється тільки частина смуги. Процес i обчислює на j-м кроці добуток i-й горизонтальної смуги матриці A j-ї вертикальної смуги матриці B, добуток отримується у підматриці (i,j) матриці C. Обчислення відбувається в такій послідовності: Головний процесор (processor 0) отримує дані (матриці А та В) з пам’яті, після чого відбувається обчислення щодо розподілу рядків матриці А та стовпців матриці В між процесорами. На наступному етапі головний процесор починає послідовно (по кільцю) надсилати решті процесорів необхідні їм для обчислення дані. По закінченню етапу завантаження даних кожен з процесорів буде містити смугу матриці А і смугу матриці В. Обчислювальний крок 1. Кожен процес обчислює одну підматрицю добутку. Вертикальні смуги матриці B зсуваються уздовж кільця процесорів. Обчислювальний крок 2. Кожен процес обчислює одну підматрицю добутку. Вертикальні смуги матриці B зсуваються уздовж кільця процесорів і т.д. Обчислювальний крок . Кожен процес обчислює одну підматрицю добутку. Вертикальні смуги матриці B зсуваються уздовж кільця процесорів. Обчислювальний крок . Кожен процес обчислює одну підматрицю добутку. Вертикальні смуги матриці B зсуваються уздовж кільця процесорів. Після виконання останнього обчислювального кроку відбувається вивантаження часткових результатів (підматриць ) до нульового процесора. Якщо "прокручувати" вертикальні смуги матриці B, то матриця С буде розподілена горизонтальними смугами, а якщо "прокручувати" горизонтальні смуги матриці A, то матриця С буде розподілена вертикальними смугами. Час на завантаження/вивантаження матриць через один процесор залежить від алгоритму завантаження вивантаження, в загальному випадку якого можна обчислити за формулою: Z = (A+B)+(p-1)(A+B)+(p-2)(A+B)… Алгоритм характерний тим, що після кожного кроку обчислень здійснюється обмін даними. Нехай , , і час операцій, відповідно, множення, додавання і пересилання одного числа між сусідніми процесорами. Тоді загальний час виконання операцій множень дорівнює: , загальний час виконання операцій додавань: , загальний час виконання операцій пересилань даних по всіх процесорах: . Загальний час обчислень визначимо як: . Якщо час передачі даних великий в порівнянні з часом обчислень, або канали передачі повільні, то ефективність алгоритму буде не висока. Тут не враховується час початкового завантаження і вивантаження даних у пам'ять системи. У смугах матриць може бути різна кількість рядків, а різниця в кількості рядків між смугами - 1. При великих матрицях цим можна знехтувати. 2. ПРОЕКТУВАННЯ ГРАФ-СХЕМИ ВИКОНАННЯ АЛГОРИТМУ На рис. 2.1 наведена узагальнена граф-схема виконання алгоритму множення двох матриць на кільцевій структурі з завантаженням через один з процесорів.  Рис. 2.1. Узагальнена граф-схема виконання алгоритму множення двох матриць на кільцевій структурі з завантаженням через один з процесорів Згідно з блок-схемою рис. 2.1 всі дані завантажуються через один процесор і пересилаються на інші. Завантаження відбувається послідовно по вибраній кільцевій структурі рис. 2.3. 0-> 5, 5->4, 4->3, 3-> 2, 2->1. Як тільки кожен процесор отримав свої смуги вхідних матриць починається процес множення. Розбиття матриць на смуги зображено на рис. 2.2. Процес обчислення складається з множення під матриць на кожному процесорі і обміні під матрицями В. Обмін відбувається за структурою зображеною на рис. 2.3 і відбувається за два кроки. Перший крок: 0->5; 4->3; 2->1. Другий крок: 5->4; 3->2; 1->0. Після перемноження початкових смуг і отримання часткових результатів відбувається перевірка на завершення процесу множення. Вона полягає в перевірці чи кожен отримав усі можливі смуги матриці В. Якщо ні, процесори обмінюються підматрицею В і продовжують обчислення. Згідно з схемою алгоритму виконується 6 разів операція обчислення і 5 разів операція пересилання підматриці В. Після завершення операції множення, відбувається збір результату на одному процесорі. Всі процесори пересилають свої часткові результати на один процесор, який вивантажує кінцевий результат в пам'ять. Операція вивантаження теж виконується послідовно по кільцевій структурі. Матриці розбиваються на смуги наступним чином: n1/p = 80/6 = 13 і 2 остача; n2/p =1040/6 = 173 і 2 остача; n3/p =100/6 = 16 і 4 остача; в результаті отримаємо наступне розбиття:  Рис. 2.2. Схема розбиття матриць А і В на смуги.  Рис. 2.3. Кільцева структура для обміну даними між процесорами. 3. РОЗРОБКА ФУНКЦІОНАЛЬНОЇ СХЕМИ Функціональна схема відображає покроковий алгоритм розподілу даних, обчислення, пересилання, збору на задній структурі. Смуги Ai i Bi вибирають згідно з розбиттям наведеним на рис. 2.2. Згідно з даною схемою процесор 0 завантажує по черзі підматриці для кожного процесора і розсилає на кожен процесор. Коли всі процесори отримали свої смуги відбувається множення з пересиланням по тій же кільцевій структурі. Після завершення множення відбувається збір результату у зворотному напрямку по відношенню до завантаження. Рис. 3.1. Узагальнена граф-схема виконання алгоритму множення матриць на кільцевій структурі 4. РОЗРАХУНКОВИЙ РОЗДІЛ Загальний час виконання алгоритму перемноження матриць на кільцевій структурі можна розрахувати за допомогою формули: T = Z + U+S+P+W, де Z - час, витрачений на завантаження даних; U - час виконання операцій множення; S - час виконання операцій сумування; P - час, витрачений на пересилання даних між процесорами; W - час, витрачений на вивантаження даних. Для процесорних елементів визначимо такі розміри підматриць: А0 = 13*1040, A1 = 13*1040, A2 = 13*1040, A3 = 13*1040, A4 =14*1040, A5 = 14*1040; B0 = 1040*16, B1 = 1040*16, B2 = 1040*17, B3 = 1040*17, B4 = 1040*17, B5 = 1040*17; С0 = 13*100, С1 = 13*100, С2 = 13*100, С3 = 13*100, С4 =14*100, С5 = 14*100. Процес завантаження даних в процесори є послідовним, тому час завантаження визначається послідовністю кроків і враховується найбільший час на кожному кроці: Крок 1: Завантаження в процесор 0 підматриці для процесора 5 Z1 = A5*B5*tz= (14*1040)+(1024*17)tz = 14560+17680tz = 32240tz = 32240tu/15= 2149,3tu Крок 2: Пересилання підматриці 5 на процесор 1 Z2 =A5*B5*tp= (14*1040)+(1024*17)tp=14560+17680tp =32240tp=32240tu/10 =3224tu; Крок 3: Так як час пересилання є більшим за час завантаження враховується час пересилання підматриці 4 Z3 =A4*B4*tp= (14*1040)+(1024*17)tp=14560+17680tp=32240tp=32240tu/10 =3224tu; Крок 4: Пересилання підматриць по заданій структурі відбувається паралельно Z4 = A4*B4*tp =(14*1040)+(1024*17)tp=14560+17680tp=32240tp=32240tu/10 =3224tu; Крок 5: Враховується час пересилання Z5 = A4*B4*tp =(14*1040)+(1024*17)tp=14560+17680tp=32240tp=32240tu/10 =3224tu; Крок 6: пересилання: Z6 = A4*B4*tp =(14*1040)+(1024*17)tp=14560+17680tp=32240tp=32240tu/10 =3224tu; Крок 7: Враховується час пересилання Z7 = A4*B4*tp =(14*1040)+(1024*17)tp=14560+17680tp=32240tp=32240tu/10 =3224tu; Крок 8: пересилання: Z8 = A3*B3*tp =(13*1040)+(1024*17)tp=13520+17680tp=31200tp=31200tu/10 =3120tu; Крок 9: Враховується час пересилання Z9 = A3*B3*tp =(13*1040)+(1024*17)tp=13520+17680tp=31200tp=31200tu/10 =3120tu; Крок 10: пересилання: Z10=A2*B2*tp=(13*1040)+(1024*16)tp=13520+16640tp=30160tp=30160tu/10 =3016tu; Крок 11: Враховується час завантаження підматриці 0 Z11 = A1*B1*tp=(13*1040)+(1024*16)tz13520+16640tz=30160tz=30160tu/15= 2010,7tu; Загальний час завантаження буде рівний Z = Z1+ Z2+Z3+Z4+Z5+Z6+Z7+Z8+Z9+Z10+Z11 = (2149,3+6*3224+2*3120+3016+2010,7)tu = (7176 + 6240+19344)tu =32760tu Множення виконується за 6 ітерацій, так як розбиття матриць є нерівномірним, то час множення на кожній ітерації буде рівним процесору, який перемножує найбільші підматриці і час обчислення буде рівний: U = (14*1040*17*5 + 14*1040*16)*tu = 1470560tu S = (14*1039*17*5+14*1039*16)*ts=1469146ts = 1469146tu/9=163238,5tu P = (n2*n3)*(p1-1)*2*tp Пересилання : P = (1040*100)*5*2*tp=1040000tp=1040000tu/10 =104000tu; Час вивантаження буде обчислюватись аналогічно часові завантаження і буде складатись з 11 кроків: Крок 1: Вивантаження з процесора 0 підматриці 0 W1 =C0*tw= (13*100)tw = 1300tw = 1300tu/5 = 260tu Крок 2: Пересилання підматриці 1 на процесор 0 W2 =C1*tp= (13*100)tp=1300tp = 130tu Крок 3: Так як час вивантаження є більшим за час пересилання враховується час вивантаження підматриці 1 W3 ==C1*tw== (13*100)tw=1300tw = 260tu; Крок 4: Пересилання підматриць по заданій структурі відбувається паралельно W4 = C3*tp=(13*100)tp=1300tp = 130tu; Крок 5: Враховується час вивантаження W5 =C2*tw=(13*100)tw=1300tw = 260tu; Крок 6: пересилання: W6 =C4*tp=(14*100)tp=1400tp = 140tu; Крок 7: Враховується час вивантаження W7 ==C3*tw== (13*100)tw=1300tw = 260tu; Крок 8: пересилання: W8 =C5*twp (14*100)tp=1400tp = 140tu; Крок 9: Враховується час вивантаження W9 =C4*tw= (14*100)tw=1400tw = 280tu; Крок 10: пересилання: W10 =C5*tp= (14*100)tp=1400tp = 140tu; Крок 11: Враховується час вивантаження підматриці 5 W11 =C5*tw= (14*100)tw=1400tw = 280tu; Загальний час завантаження буде рівний W = W1+ W2+W3+W4+W5+W6+W7+W8+W9+W10+W11 = 130*2+140*3+260*5+280*2 = 420+1560+560=2540tu Загальний час виконання всіх операцій буде рівний: T = 32760tu+1470560tu+163238,5tu+104000tu+2540tu = 1773098,5tu Для порівняння обчислимо умовний час виконання послідовного алгоритму: Час завантаження і час вивантаження будуть такими ж як і в паралельному алгоритмі без пересилань: Zпос = (80*1040 + 1040* 100)tz = 187200tz = 187200tu/15. = 12480tu Wпос = (80* 100)tw =.8000tw = 8000tu/5. = 1600tu Пересилань ніяких не буде, тому час пересилання Pпос = 0. Час множення буде рівним: Uпос = (N1*N2*N3) * tU = (80*100*1040)*tu = 8320000tu; Час додавання буде рівним: Sпос = (N1*N2*N3-1) * tS = (80*100*1039)*ts = 8312000ts=923555,5tu Tпос = Zпос + Uпос + Sпос + Wпос = (12480 + 8320000 + 923555,5 + 1600) * tu = 9257635,5 * tw Час виконання послідовного алгоритму перемноження однакових матриць на одному процесорі приблизно в 9282435,5/1773098,5 ≈ 5,24 раз більший, ніж паралельного алгоритму. Для характеристики алгоритму визначимо коефіцієнт К, який характеризує відсоток послідовних обчислень. В нашому випадку він буде рівний: K = (Z+W+P) / T = (32760 + 2540+104000) / 1773098,5≈ 0,083 = 7,8%. Також порахуємо ефективність паралельного алгоритму. Ефективність визначається, як відношення часу виконання алгоритму на одно процесорній системі, до часу потрібного для виконання на багатопроцесорної системі, помноженого на кількість процесорів в ній. E = TПОС / (T * p) = 9282435,5/(1773098,5*6) ≈ 0,87. 5. РОЗРОБКА ПРОГРАМИ Першим кроком розробки програми для виконання заданої функції є розробка блок схеми алгоритму.  Рис. 5.1.Блок-схема роботи програми. Згідно з блок-схемою програма повинна завантажувати дані через один процесор і розсилати їх на всі процесори згідно з вибраним алгоритмом. Після розсилання даних відбувається шість циклів перемноження матриці. Після того як на кожному процесорі сформується результуючі підматриці всі дані збираються на одному процесорі. Для реалізації даної програми використовується бібліотека MPI. Всі пересилання виконуються за допомогою функції MPI_Send, а прийом повідомлень виконується функцією MPI_Recv. Дана програма написана на мові С++ в середовищі розробки MS Visual Studio 2010 і має консольний інтерфейс. Результати роботи програми:  Рис. 5.1 Результати роботи програми. Завантаження даних на процесори відбувається з файла. Файл був заздалегідь згенерований. Як видно з рис.5.1 програма працює коректно і видає результати множення. ВИСНОВКИ В ході виконання даної курсової роботи розробила структуру перемноження двох матриць на кільцевій структурі та її програмну реалізацію. Також провела деякі обчислення, які дають уявлення про характеристики даного паралельного алгоритму. В результаті проведеної роботи можна зробити такі висновки: для шестипроцесорної системи та матриць з розмірами ,  умовний час виконання програми в інтервалах виконання операції додавання виявився рівним T=1773098,5tu, а відсоток послідовних операцій програми f становить 7,8 %. Ефективність при цьому рівна E=0,87, що є досить хорошим показником, але не ідеальним. ЛІТЕРАТУРА Бройнль Т. Паралельне програмування: Початковий курс: Навчальний посібник. – К.:Вища школа., 1997. Корнеев В. В. Параллельные вычислительные системы. М.: Нолидж, 1999. С. Немнюгин, О. Стесик Параллельное программирование для многопроцессорных вычислительных систем. – СПб: БХВ-Петербург, 2002. Воеводин В. В., Воеводин Вл. В. Параллельные вычисления. – СПб: БХВ-Петербург, 2002. Гергель В. П. Теория и практика параллельных вычислений. М.: БИНОМ. Лаборатория знаний, Интернет-университет информационных технологий - ИНТУИТ.ру, 2007, 424 с. Організація паралельних обчислень : Навчальний посібник з дисципліни “Паралельні та розподілені обчислення” для студентів базового напрямку 6.0915 "Комп'ютерна інженерія" / Укладачі: Є. Ваврук, О. Лашко – Львів: Національний університет “Львівська політехніка”, 2007, 70 с. Додатки Лістинг програми: // MPI.cpp : Defines the entry point for the console application. // #include <stdio.h> #include <stdlib.h> #include <iostream> #include <mpi.h> using namespace std; int ProcNum = 6; int ProcRank; double* pProcRows; const int N1 = 80; const int N2 = 1040; const int N3 = 100; int pRowsA[] = {13,13,13,13,14,14}; int pColsB[] = {16,16,17,17,17,17}; int pSendNumSubA[] = {13*1040,13*1040,13*1040,13*1040,14*1040,14*1040}; int pSendIndSubA[] = {0,13*1040,2*13*1040,3*13*1040,4*13*1040,4*13*1040+14*1040}; int pSendNumSubB[] = {1040*16,1040*16,1040*17,1040*17,1040*17,1040*17}; int pSendIndSubB[] = {0,1040*16,2*1040*16,2*1040*16+1040*17,2*1040*16+2*1040*17,2*1040*16+1040*17}; int pSendNumSubC[] = {N1*N3/8,N1*N3/8,N1*N3/8,N1*N3/8,N1*N3/8,N1*N3/8,N1*N3/8,N1*N3/8}; const int pResInd[] = {0,16,32,49,66,83}; const int ProcNumber = 6; void ReadMemory(double* pMatrixA,double* pMatrixB){ FILE *Ptr; int temp; Ptr=fopen("mass.txt","r"); for(int i=0;i<N1*N2;i++) { fscanf(Ptr,"%d",&temp); pMatrixA[i] = (double)temp; } for(int i=0;i<N2*N3;i++) { fscanf(Ptr,"%d",&temp); pMatrixB[i] = (double)temp; } fclose(Ptr); } void Calc (double * pMatrixA, double * pMatrixB, double * pMatrixB1, double * pProcResult, double * pResult1, int iIndex); int main(int argc, char* argv[]) { double* pMatrixA; // Перший аргумент - початкова матриця double* pMatrixB; // Другий аргумент - початковий вектор double* pResult; // Результат множення матриці на вектор double* pProcRows; double* pProcResult; double* pResult1=new double[N1*N3]; int *pSendNum = new int[ProcNumber]; int *pSendInd = new int[ProcNumber]; int RowNum; pProcRows = new double[N1*N2*6]; pMatrixA = new double[N1*N2]; pMatrixB = new double[N2*N3]; pResult = new double[N1*N3]; pProcResult = new double[(N1/8)*N3]; double* pMatrixB1 = new double[N2*N3*6]; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &ProcNum); MPI_Comm_rank(MPI_COMM_WORLD, &ProcRank); for(int i=0; i<N2*N3; i++){ pMatrixB[i]=0; } if(ProcRank==0){ //Заповнення матриць ReadMemory(pMatrixA, pMatrixB); } //--------------------------------------------------------- int Index = 0; Calc (pMatrixA, pMatrixB, pMatrixB1, pProcResult, pResult1, iIndex); //----------------------------------------------------------- MPI_Finalize(); return 0; } void Calc( double * pMatrixA, double * pMatrixB, double * pMatrixB1, double * pProcResult, double * pResult, int iIndex) { //Data Distribution MPI_Status status; if(ProcRank==0){ MPI_Send(pMatrixA,pSendNumSubA[5]+pSendNumSubA[4]+pSendNumSubA[3]+pSendNumSubA[2]+pSendNumSubA[1],MPI_DOUBLE,5,0,MPI_COMM_WORLD); MPI_Send(pMatrixB,pSendNumSubB[5]+pSendNumSubB[4]+pSendNumSubB[3]+pSendNumSubB[2]+pSendNumSubB[1],MPI_DOUBLE,5,2,MPI_COMM_WORLD); for(int i=0;i<pSendNumSubA[0];i++) pProcRows[i] = pMatrixA[i]; for(int i=0;i<pSendNumSubB[0];i++) pMatrixB1[i] = pMatrixB[i]; } if(ProcRank==5){ MPI_Recv(pProcRows,pSendNumSubA[5]+pSendNumSubA[4]+pSendNumSubA[3]+pSendNumSubA[2]+pSendNumSubA[1],MPI_DOUBLE,0,0,MPI_COMM_WORLD,&status); MPI_Recv(pMatrixB1,pSendNumSubB[5]+pSendNumSubB[4]+pSendNumSubB[3]+pSendNumSubB[2]+pSendNumSubB[1],MPI_DOUBLE,0,2,MPI_COMM_WORLD,&status); MPI_Send(pProcRows+pSendNumSubA[5],pSendNumSubA[4]+pSendNumSubA[3]+pSendNumSubA[2]+pSendNumSubA[1],MPI_DOUBLE,4,0,MPI_COMM_WORLD); MPI_Send(pMatrixB1+pSendNumSubB[5],pSendNumSubB[4]+pSendNumSubB[3]+pSendNumSubB[2]+pSendNumSubB[1],MPI_DOUBLE,4,2,MPI_COMM_WORLD); } if(ProcRank==4){ MPI_Recv(pProcRows,pSendNumSubA[4]+pSendNumSubA[3]+pSendNumSubA[2]+pSendNumSubA[1],MPI_DOUBLE,5,0,MPI_COMM_WORLD,&status); MPI_Recv(pMatrixB1,pSendNumSubA[4]+pSendNumSubA[3]+pSendNumSubA[2]+pSendNumSubA[1],MPI_DOUBLE,5,2,MPI_COMM_WORLD,&status); MPI_Send(pProcRows+pSendNumSubA[4],pSendNumSubA[3]+pSendNumSubA[2]+pSendNumSubA[1],MPI_DOUBLE,3,0,MPI_COMM_WORLD); MPI_Send(pMatrixB1+pSendNumSubB[4],pSendNumSubB[3]+pSendNumSubB[2]+pSendNumSubB[1],MPI_DOUBLE,3,2,MPI_COMM_WORLD); } if(ProcRank==3){ MPI_Recv(pProcRows,pSendNumSubA[3]+pSendNumSubA[2]+pSendNumSubA[1],MPI_DOUBLE,4,0,MPI_COMM_WORLD,&status); MPI_Recv(pMatrixB1,pSendNumSubA[3]+pSendNumSubA[2]+pSendNumSubA[1],MPI_DOUBLE,4,2,MPI_COMM_WORLD,&status); MPI_Send(pProcRows+pSendNumSubA[3],pSendNumSubA[2]+pSendNumSubA[1],MPI_DOUBLE,2,0,MPI_COMM_WORLD); MPI_Send(pMatrixB1+pSendNumSubB[3],pSendNumSubB[2]+pSendNumSubB[1],MPI_DOUBLE,2,2,MPI_COMM_WORLD); } if(ProcRank==2){ MPI_Recv(pProcRows,pSendNumSubA[2]+pSendNumSubA[1],MPI_DOUBLE,3,0,MPI_COMM_WORLD,&status); MPI_Recv(pMatrixB1,pSendNumSubA[2]+pSendNumSubA[1],MPI_DOUBLE,3,2,MPI_COMM_WORLD,&status); MPI_Send(pProcRows+pSendNumSubA[2],pSendNumSubA[1],MPI_DOUBLE,1,0,MPI_COMM_WORLD); MPI_Send(pMatrixB1+pSendNumSubB[2],pSendNumSubB[1],MPI_DOUBLE,1,2,MPI_COMM_WORLD); } if(ProcRank==1){ MPI_Recv(pProcRows,pSendNumSubA[1],MPI_DOUBLE,2,0,MPI_COMM_WORLD,&status); MPI_Recv(pMatrixB1,pSendNumSubA[1],MPI_DOUBLE,2,2,MPI_COMM_WORLD,&status); } cout << "P" << ProcRank << endl; for(int i=0;i<pSendNumSubA[ProcRank];i++) { cout << pProcRows[i] << " "; } cout << endl; //обнулення проміжних результатів for(int i=0; i<N1/8; i++) for(int j=0; j<N3+1; j++) pProcResult[i*N3+j]=0; //множення і обмін підматрицями В if (ProcRank==0){ for(int i=0; i<pRowsA[0]; i++) for(int j=0; j<pColsB[0]; j++) for(int k=0; k<N2; k++) pProcResult[i*N3+j+pResInd[0]]+=pProcRows[i*N2+k]*pMatrixB1[j*N2+k]; MPI_Send(pMatrixB1,pSendNumSubB[0],MPI_DOUBLE,5,0,MPI_COMM_WORLD); MPI_Recv(pMatrixB1,pSendNumSubB[1],MPI_DOUBLE,1,0,MPI_COMM_WORLD,&status); for(int i=0; i<pRowsA[0]; i++) for(int j=0; j<pColsB[1]; j++) for(int k=0; k<N2; k++) pProcResult[i*N3+j+pResInd[1]]+=pProcRows[i*N2+k]*pMatrixB1[j*N2+k]; MPI_Send(pMatrixB1,pSendNumSubB[1],MPI_DOUBLE,5,0,MPI_COMM_WORLD); MPI_Recv(pMatrixB1,pSendNumSubB[2],MPI_DOUBLE,1,0,MPI_COMM_WORLD,&status); for(int i=0; i<pRowsA[0]; i++) for(int j=0; j<pColsB[2]; j++) for(int k=0; k<N2; k++) pProcResult[i*N3+j+pResInd[2]]+=pProcRows[i*N2+k]*pMatrixB1[j*N2+k]; MPI_Send(pMatrixB1,pSendNumSubB[2],MPI_DOUBLE,5,0,MPI_COMM_WORLD); MPI_Recv(pMatrixB1,pSendNumSubB[3],MPI_DOUBLE,1,0,MPI_COMM_WORLD,&status); for(int i=0; i<pRowsA[0]; i++) for(int j=0; j<pColsB[3]; j
Антиботан аватар за замовчуванням

26.03.2013 10:03-

Коментарі

Ви не можете залишити коментар. Для цього, будь ласка, увійдіть або зареєструйтесь.

Ділись своїми роботами та отримуй миттєві бонуси!

Маєш корисні навчальні матеріали, які припадають пилом на твоєму комп'ютері? Розрахункові, лабораторні, практичні чи контрольні роботи — завантажуй їх прямо зараз і одразу отримуй бали на свій рахунок! Заархівуй всі файли в один .zip (до 100 МБ) або завантажуй кожен файл окремо. Внесок у спільноту – це легкий спосіб допомогти іншим та отримати додаткові можливості на сайті. Твої старі роботи можуть приносити тобі нові нагороди!
Нічого не вибрано
0%

Оголошення від адміністратора

Антиботан аватар за замовчуванням

Подякувати Студентському архіву довільною сумою

Admin

26.02.2023 12:38

Дякуємо, що користуєтесь нашим архівом!