Процесс компиляции собственного программного обеспечения для работы с PVM

Для того, чтобы писать программы для исполнения в параллельной вычислительной машиной следует использовать стандартные вызовы библиотеки pvm3.h, необходимо указывать дополнительный набор ключей для осуществления процесса компиляции ПО. Компиляция ПО проводилась в Qt-creator. Дополнительный набор ключей указывался в *.pro файле проекта: QMAKE_LIBS += -lpvm3 -lrt.

Обязательным условием для гетерогенных установок является компиляция исходных кодов ПО для каждой системы в отдельности, в нашем случае LINUX64. Далее следует разослать на все узлы кластера исполняемый файл, т.е. скопировать его в каталог ~/pvm3/bin/LINUX64 на каждом узле.

4) Тестирование новой конфигурации вычислительной системы.

В этом разделе результаты теста новой конфигурации будут сравниваться с результатами теста предыдущей конфигурации, для выявления прироста или ухудшения производительности, в зависимости от тех или иных параметров.

5) Нагрузочное тестирование сети.

Сначала выполняется нагрузочного тестирования сети, как самого слабого звена в структуре кластера. Для этого был реализован параллельный алгоритм решения квадратного уравнения, коэффициентами которого являются случайные вещественные числа. Исходный текст программы был дополнен необходимыми изменениями, связанными с параметрами работы PVM, и представлен в Приложении к данной работе.

Для выявления участков работы кластера предлагается несколько коэффициентов. Kp - отношение количества расчетов на узле к количеству посылок данных по сети. Kt - отношение суммарного процессорного времени к астрономическому времени работы главного процесса.

Коэффициент Kp – не меняется при данном тестировании по отношению к предыдущему. Коэффициент Kt используется для анализа прироста производительности кластера с учетом новой конфигурации системы и новыми условиями работы тестовой программы. Под новыми условиями работы понимается следующее: в старой конфигурации кластера процессы на разных узлах кластера предавали сообщения друг другу обычным способом, через посредника – демон pvmd, в новой конфигурации кластера программа скомпилирована таким образом, чтобы механизм коммуникаций между задачами работал на прямую, минуя демон pvmd, т.е. каждая задача самостоятельно предает нужные данные другим задачам и соответственно делают также. Таким образом, достигается значительный выигрыш в производительности всей кластерной системы при расчете на ней сильно связанной задачи, требующей частой синхронизации процессов. Об этом свидетельствуют следующие факторы:

1) Скорость пересылки информации по сети увеличивается с 1,5 МБайт/с (10 Мбит/c) до 7,5 Мбайт/с (60 Мбит/с), данный показатель был зафиксирован в Системном мониторе Ubuntu, где отражается статистика загрузки сети. 

2) В новой конфигурации коэффициент Kt значительно увеличивается в процентном отношении к старой конфигурации, о чем свидетельствуют приведенный ниже таблицы результатов тестирования и диаграммы, динамики прироста (рис.2) и общей динамики данного коэффициента (рис.3)

Обычная связь процессов старая конфигурация

Количество процессов

Посылок по сети, B

Расчетов на узле, С

Время работы главного процесса (астрономическое),D

Суммарное процессорное время кластера, Е

Kp = log(C/B)

Kt1 = E/D

18

1,00E+00

1,00E+09

99,10054

1186,258957

9

11,97026

18

1,00E+01

1,00E+08

112,6868

1058,926276

7

9,397075

18

1,00E+02

1,00E+07

107,7564

1038,060469

5

9,633397

18

1,00E+03

1,00E+06

113,0704

1033,268205

3

9,13827

18

1,00E+04

1,00E+05

144,8674

1038,608148

1

7,16937

18

1,00E+05

1,00E+04

341,0926

1115,252644

-1

3,269648

18

1,00E+06

1,00E+03

1592,878

1791,672389

-3

1,124802

18

1,00E+07

1,00E+02

14682,29

8547,911557

-5

0,582192

18

1,00E+08

1,00E+01

144365,1

74368,11773

-7

0,515139

Прямая связь процессов новая конфигурация

 
Количество процессов

Посылок по сети, B

Расчетов на узле, С

Время работы главного процесса (астрономическое),D

Суммарное процессорное время кластера, Е Kp = log(C/B) Kt2 = E/D  
18

1

1000000000

119,7327823

1107,298489 9 9,248081  
18

10

100000000

139,0967096

1058,176217 7 7,607486  
18

100

10000000

127,1325296

1018,450738 5 8,010937  
18

1000

1000000

147,4517699

1092,258965 3 7,407568  
18

10000

100000

212,6682274

1212,215327 1 5,70003  
18

100000

10000

387,8083071

1385,465934 -1 3,572554  
18

1000000

1000

1702,352634

3398,62797 -3 1,99643  
18

10000000

100

15483,53345

22804,68602 -5 1,472835  
18

100000000

10

114135,2611

165196,0456 -7 1,447371  
                       

 


Обобщение результатов таблинчых значений:

Количество процессов Посылок по сети, B Расчетов на узле, С Kt2/Kt1 Динамика Kt, %
1 18 1 1000000000 77% -23
2 18 10 100000000 81% -19
3 18 100 10000000 83% -17
4 18 1000 1000000 81% -19
5 18 10000 100000 80% -20
6 18 100000 10000 109% 9
7 18 1000000 1000 177% 77
8 18 10000000 100 253% 153
9 18 100000000 10 281% 181

Из диаграммы видно, что при значении посылок сообщений по сети больше 100 тысяч, наблюдается значительный прирост коэффициента Kt. Таким образом, за счет прямой коммуникации задач в PVM эффективность кластерной системы возрастает при очень высокой связности вычислений. Небольшой снижение в динамике коэффициента Kt при малом количестве посылок по сети связано с тем, что время, затраченное на отправку сообщения: инициализация буфера передачи, упаковка сообщения, отсылка – приплюсовывается ко времени счета данной задачи, так как она сама выполняет эти действия, в то время как при старой конфигурации кластера эти действия за нее выполнял демон. Если оценивать такой показатель, как Астрономическое время работы главного процесс (D), то данный параметр также уменьшается при значительном увеличении количества посылок по сети, что видно из табличных значений. Также из них видно, что суммарное процессорное время кластера (Е) увеличивается при новой конфигурации, т.е. кластер считает дольше, но зато повышается эффективность его использования при сильно связанных вычислениях, так как значение коэффициента Kt стремится к значениям меньше 1 медленно, с ростом числа посылок по сети, по сравнению с предыдущей конфигурацией кластера, когда оно достигало их уже при миллионе пересылок по сети. Если значение коэффициента Kt становится меньшим 1, это говорит о том, что данную задачу затратно решать данным способом на кластере, так как скорость счета одной машины становиться больше скорости счета всей кластерной системы в целом, что видно из табличных значений старой конфигурации. Данный прирост производительности кластера не является предельным, зависит от коэффициента Kp, например, одном из тестирований он был равен log(100/10000) = -2, то Kt возрос на 259% от старой конфигурации.

    Графическая консоль XPVM.

Поначалу этого нагрузочного тестирования сети в работе использовалась графическая консоль (XPVM). Данная консоль содержит все те же самые наборы атрибутов и функций, что и обычна консоль PVM, только они представлены в графическом виде, в качестве кнопок и графиков.

Окно графической консоли разделено на две части. В верхней части сосредоточены кнопки управления кластером, а также наглядно представлена конфигурация кластерной системы в виде хостов. Когда они бездействуют, светятся белым, когда считают, зеленым. Нижняя часть она разделана на две взаимосвязанных части. Левая часть содержит номера TID запущенных задач, а правая иллюстрирует их поведение: пустая белая полоса задача запущена, зеленая - считается, красная – передает информацию, черные линии, отходящие от плоской задачи, свидельствуют об обмене информацией с другими задачами.

Данная графическая консоль достаточно хорошо иллюстрирует работу PVM. Значительным недостатком ее является то, что при большой связности задачи XPVM не эффективно использовать в виду того, что она каждое событие сохраняет в своей памяти и затем иллюстрирует на экране, с большой задержкой в силу, отсутствия возможности более быстрого способа иллюстрации, а также в виду того что при больших посылках по сети, она начинает использовать все больше и больше ресурсов компьютерной памяти (физической и виртуальной), когда они заканчивается на главном узле кластера, то локальные задачи теряют связь с главной задачей, они зависают в памяти узлов кластера, и все расчеты соответственно останавливаются. Ввиду этого негативного воздействия, данная графическая консоль более не использовалась, т.к. она очень затратная по компьютерным ресурсам.

Иллюстрация графической консоли XPVM. (рис.4)

1.5.1. Тест имитационной модели метода Монте-Карло.

Имитационная модель метода Монте-Карло, широко применяющегося при решении задач математической физики. В качестве модельной задачи взяли последовательный алгоритм для нахождения числа Пи: случайным образом генерируем два числа из отрезка [0,1] — это координаты точки, проверяется, попадает ли эта точка в соответствующий сектор единичной окружности, если да — к счетчику прибавляется единица. Число Пи ищется как значение счетчика после проверки всех точек, умноженное на четыре и деленное на общее количество точек в опыте. Погрешность нахождения Пи уменьшается с ростом количества точек в опыте.

Данный алгоритм полностью подвергается распараллеливанию из-за того, что область данных можно разбить на не пересекающиеся отрезки, в него были добавлены те же изменения, что и в предыдущую программу нагрузочного тестирования сети. В опыте изменяется сразу две величины: первое - увеличивается количество точек, задействованных в эксперименте, с  106 до 1010 и второе - увеличивается количество расчетных процессов в кластере с 9 до 90.

Для оценки новой конфигурации кластера использовались два значения выводимые программой:

1) Среднее процессорное время кластера (Е).

Кол-во процессов Общее количество точек на кластер Среднее Проц-Время кластера Старое, E1 Среднее Проц-Время кластера Новое, Е2 E1-E2
9 1000000 0,068295269 0,068040326 0,00
18 1000000 0,068048359 0,070339206 0,00
27 1000000 0,069430465 0,071388097 0,00
36 1000000 0,071551692 0,073252535 0,00
45 1000000 0,073866028 0,074620868 0,00
54 1000000 0,075496824 0,075872485 0,00
63 1000000 0,077019329 0,077618713 0,00
72 1000000 0,07928147 0,078803145 0,00
81 1000000 0,079825395 0,080585617 0,00
90 1000000 0,081010961 0,081267964 0,00
9 10000000 0,661045693 0,647701333 0,01
18 10000000 0,675413639 0,673377255 0,00
27 10000000 0,67726336 0,656369116 0,02
36 10000000 0,69438044 0,645981136 0,05
45 10000000 0,702692726 0,671263983 0,03
54 10000000 0,704552913 0,680988712 0,02
63 10000000 0,721303162 0,674876851 0,05
72 10000000 0,72625546 0,683088815 0,04
81 10000000 0,733851275 0,685225308 0,05
90 10000000 0,737615887 0,687342186 0,05
9 100000000 6,139807484 5,950953849 0,19
18 100000000 6,181287627 6,03603047 0,15
27 100000000 6,212874967 5,999045691 0,21
45 100000000 6,216053396 6,067578798 0,15
63 100000000 6,134568011 6,073195363 0,06
Кол-во процессов Общее количество точек на кластер Среднее Проц-Время кластера Старое, E1 Среднее Проц-Время кластера Новое, Е2 E1-E2
72 100000000 6,17565295 6,053301312 0,12
81 100000000 6,214479306 6,058565829 0,16
90 100000000 6,230372889 6,07777647 0,15
9 1000000000 62,19087335 59,38107455 2,81
18 1000000000 62,29993233 59,23171841 3,07
27 1000000000 63,43304354 59,28884506 4,14
36 1000000000 62,11486847 59,19742158 2,92
45 1000000000 64,15349547 59,19926148 4,95
54 1000000000 63,90943245 59,21409718 4,70
63 1000000000 61,92625735 59,39892504 2,53
72 1000000000 63,87289228 59,29861706 4,57
81 1000000000 63,78063174 59,28395371 4,50
90 1000000000 61,7612 59,28268173 2,48
9 10000000000 611,8024851 592,4171916 19,39
18 10000000000 625,3053222 592,4245721 32,88
27 10000000000 639,5959873 595,1258813 44,47
36 10000000000 637,4668521 591,0551191 46,41
45 10000000000 641,7515958 595,0374052 46,71
54 10000000000 639,0328503 594,7466575 44,29
63 10000000000 641,5984646 595,4592241 46,14
72 10000000000 640,4067908 594,5784957 45,83
81 10000000000 647,1050188 595,1500482 51,95
90 10000000000 649,7285772 595,5870165 54,14
         

 

Из данной таблицы видно, что среднее процессорное время старой конфигурации кластера (Е1) больше, чем новой (E2), при любом числе запущенных процессов. Это проиллюстрировано на диаграммах (рис.5). Следует также отметить тот факт, что при количестве точек большем 1 миллиарда, число запущенных процессов практически не влияет на время счета задачи на кластерной системе, т.е. сколько бы мы процессов счета не запустили, время счета всей кластерной системы останется практически неизменным, а если увеличить число точек (увеличилось в 10 раз), то время счета увеличится во столько раз, во сколько увеличилось число точек (с 59 до 590), об этом свидетельствуют последние две диаграммы (рис.5), такой явной, прямой зависимости при тестировании предыдущей конфигурации не наблюдалось.

 

2)  Среднее астрономическое время мастера (D), т.е. время работы главной задачи.

Множитель числа процессов Среднее Астро время мастера старое, D1 Среднее Астро время мастера старое, D2 Динамика D2/D1, %
1 0,022743768 0,032634701 43,49
2 0,019742664 0,03169092 60,52
3 0,021301948 0,034691644 62,86
4 0,024832952 0,040115372 61,54
5 0,028491408 0,045345944 59,16
6 0,029647164 0,051315045 73,09
7 0,033450504 0,05683616 69,91
8 0,036737372 0,063799631 73,66
9 0,042951404 0,068065941 58,47
10 0,043405036 0,075527723 74,01
1 0,103664444 0,202463692 95,31
2 0,11484904 0,165041815 43,70
3 0,127870064 0,159635056 24,84
4 0,134409268 0,164022045 22,03
5 0,12639482 0,17818776 40,98
6 0,116823392 0,180488963 54,50
7 0,130211992 0,173872781 33,53
8 0,12740668 0,18057806 41,73
9 0,140798348 0,175055627 24,33
10 0,142984988 0,176062221 23,13
1 0,700494568 0,88411162 26,21
2 0,547940688 0,675269863 23,24
3 0,5114647 0,611737833 19,61
4 0,488551472 0,54348774 11,24
5 0,518046152 0,584736824 12,87
6 0,551513784 0,535651952 -2,88
7 0,575195352 0,550129908 -4,36
8 0,610063008 0,549478912 -9,93
9 0,592967288 0,5678019 -4,24
10 0,564720308 0,539328296 -4,50
1 7,264334296 8,459022909 16,45
2 5,388554972 6,425114483 19,24
3 4,501883604 5,537003825 22,99
4 4,138298968 4,9413291 19,40
5 3,92861094 4,767840401 21,36
6 3,843623388 4,602281532 19,74
7 3,829017744 4,507728879 17,73
Множитель числа процессов Среднее Астро время мастера старое, D1 Среднее Астро время мастера старое, D2 Динамика D2/D1, %
8 3,793960948 4,397511392 15,91
10 3,69318834 4,190045288 13,45
1 89,95403528 75,49142178 -16,08
2 46,51671818 57,16418391 22,89
3 48,92022383 51,29661245 4,86
4 46,58261083 47,41044204 1,78
5 47,46935875 50,82233079 7,06
6 47,406562 45,80383927 -3,38
7 48,7799673 43,59741354 -10,62
8 47,51148996 42,6926881 -10,14
9 48,393231 42,1579862 -12,88
10 47,43611276 41,95229874 -11,56

Данный показатель имеет значения хуже, чем в старой конфигурации, но стремится к ее значениям с ростом количества точек участвующих в расчетах (рис.6,7), т.е. данный показатель можно считать практически неизменившимся, если брать в расчет количество точек равное 108, 109, 1010.

Динамика среднего астрономического времени работы главной задачи  (рис.6).

 

Таким образом, тест имитационной модели метода Монте-Карло показал, что практически при тех же значениях среднего астрономического времени работы главной задачи, среднее процессорное время работы кластера над данной задачей уменьшается, отсюда можно сделать вполне  обоснованный вывод, что кластерная система в новой конфигурации работает быстрее.

Заключение.

В ходе работы были изучены основные принципы построения распределенных вычислительных систем (HPC), оптимизирована работа параллельной виртуальной машины PVM на базе компьютеризированной лаборатории физического факультета: установлено новое программное обеспечение, изучен интерфейс и принципы работы графической консоли XPVM, дана оценка сферы ее применимости, оптимизирован алгоритм тестовых программ, повышены показатели производительности кластерной системы. Поставленные цели и задачи курсовой работы достигнуты.

 

 

Список литературы.

1. PVM User’s Guide: http://www.netlib.org

2. Онлайн энциклопедия: http://ru.wikipedia.org/

3. Linux кластер – практическое руководство: http://cluster.linux-ekb.info/

4. Илья Евсеев - Использование PVM. Введение в программирование: http://www.cluster.bsu.by

5. Программа СКИФ союзного государства. PVM - параллельная виртуальная машина: http://www.skif.bas-net.by

6. Балуев А.Н. Перевод документации по PVM (мат-мех факультет СПбГУ): http://www.math.spbu.ru

7. Message Passing Toolkit: PVM Programmer's Manual: http://techpubs.sgi.com

8. Шпаковский Г.И., Серикова Н.В. Пособие по программированию матричных задач в MPI.  - Минск: БГУ, - 2002. – 44 с.

Приложение.

Текст программы, использованной для нагрузочного тестирования сети:

//программа для нагрузочного тестирования запускается из консоли (кол-во посылок, решения)

#include <stdio.h>

#include <stdlib.h>

#include "pvm3.h"

#include "math.h"

#include <time.h>

 //идентификаторы

#define msgtype_argv 0

#define msgtype_master_data 1

#define msgtype_slave_data 2

#define msgtype_slave_time 3

double x[2];                  //массив для хранения решений кв.ур-ия

double timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p)

{

return ((double)(timeA_p->tv_sec) + ((double)(timeA_p->tv_nsec))/1000000000)-((double)(timeB_p->tv_sec) + ((double)(timeB_p->tv_nsec))/1000000000);

}

int main(int argc, char *argv[])

{

   int mytid;   //переменная для иденификации основного процесс

   int tids[100]; //массив значений tids для запущенных задач

   long int N/*кол-во повторов решения на узле*/, i, j, k, np/*кол-во посылок по сети*/;

   int nslaves/*число запущенныйх задач*/, nhosts/*количество хостов*/, narch/*количество различных форматов данных*/, master;

   void raschet(double a, double b, double c); //к решению квадратного ураванения(коэффициенты a,b,c)))

   double total_time_cpu_c=0;       //общее время процессора

   double time_cpu_master_c=0; //общее время работы процессора на локальных узлах

   double time_global_master_l=0;         //число тактов процессора на решение задачи

   double time_slave_ci=0;                                                                  //время работы процессора на локальном узле

   struct pvmhostinfo *hostp;                                                                  //При возврате, каждая структура pvmhostinfo содержит TID pvmd, имя хоста, имя архитектуры и относительную характеристику скорости процессора для определенного хоста в конфигурации

   struct timespec start_c, start_l, end_l, end_c, start_ci, end_ci;

   clock_gettime(CLOCK_MONOTONIC, &start_l);                                                                  //старт точного измерения тактов процессора

   clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_c);                                                                  //старт счета процессорного времени на решение задачи

   mytid = pvm_mytid();                                                                  //регистрирует процесс в PVM, возвращает TID текущего процесса

pvm_setopt(PvmRoute, PvmRouteDirect);                              //``включение'' прямолинейной маршрутизации между задачами PVM

pvm_setopt(PvmFragSize,16384);                       //установить размер буфера передачи для сообщения

//pvm_setopt(PvmFragSize,65536);                   // субъективный параметр на скорость передачи не влияет

//pvm_setopt(PvmFragSize,114688);                    //хуже

//pvm_setopt(PvmFragSize,163840); //

//pvm_catchout(stdout);                                         // для вывода на экран информации от подзадач

//pvm_setopt(PvmOutputTid,0);

                                                                          //инициализация генератора псевдослучайных чисел

   srand((unsigned)time(NULL));                                                                  //time() возвращает текущее время в сек

   long double a, b, c;                                                                  //переменные под коэффициенты кв.ур-ия

                                                                          //определение местоположения для выполнения соответствующей части задачи.

                                                                          //pvm_parent() - вернет TID задачи, которая породила задачу, сделавшую вызов

   if(pvm_parent() == PvmNoParent)                                                                  //если выполница, то это задача - главная порождающая остальные

   {

                                                                          //1 часть программы для главного узла

           pvm_config(&nhosts, &narch, &hostp);                                                                  //возвращает информацию о виртуальной машине, включая количество хостов - nhost - и количество различных форматов данных - narch

//printf("%s \n",argv[0]);

            /*&hostp - это указатель на декларированный пользователем массив из структур pvmhostinfo.

           Размер массива должен быть длиной, по крайней мере, соответствующей nhosts.*/

                                                                                  //считывает число посылок по сети

           sscanf(argv[1],"%lu",&np);                                                                  //читает данные из argv[1], преобразовывая символы к значениям указателей на long unsigned int, в переменную np

                                                                                  //считывает число решений на одном узле

           sscanf(argv[2],"%lu",&N);                                                                  //

           nslaves = 2*nhosts -1;                                                                  //число запусков задач(2*число хостов-1)

printf("%d \t", nslaves+1);                                                                  //печатаеть в stdout целочисленные десятичные наборы сиволы через таб длинной nslaves+1

printf("%lu\t%lu\t",np,N);                                                                  //печатаеть в stdout long unsigned int наборы сиволы через tab и tab из преременных np и N

           nslaves=pvm_spawn(&argv[0][0], (char**)0, 0, "", nslaves, tids);                                                                  //ф-ция,которая запускает в PVM nslaves копий исполняемого файла с именем "argv[0][29]" с одинаковыми аргументами командной строки (char**)0, на компьютере который выберет сама.

//отсылка

           pvm_initsend(PvmDataInPlace);                                                                  //инициализация буфера для отправки сообщения

           pvm_pklong(&N, 1, 1);                                                                  //упаковка в передающий буфер данных массива N длинной 1 с числом элементов 1 в одном эл-те массива

           pvm_pklong(&np, 1, 1);

           pvm_mcast(tids, nslaves, msgtype_argv);                                                                  //присваевает сообщению идентификатор msgtype_argv и широковещательно посылает его задачам, идентификаторы которых перечислены в nslaves элементах массива tids

                                                                                  //цыклы для посылки по рассылки

           for(j = 0; j < np; j++)

           {

                                                                                          //задаем коэффициенты через rand

                   for(i = 0; i < nslaves; i++)

                     {

                     a = ((long double) rand() /((long double)RAND_MAX+1.0));

                     b = ((long double) rand() /((long double)RAND_MAX+1.0));

                     c = ((long double) rand() /((long double)RAND_MAX+1.0));

                                     pvm_initsend(PvmDataInPlace);                                                                  //инициализация буфера пересылки

                                     pvm_pklong((long int *)(&a), 2, 1);                                                                    //упаковка созданного коэф-та а

                                     pvm_pklong((long int *)(&b), 2, 1);                                                                  //упаковка созданного коэф-та b

                                     pvm_pklong((long int *)(&c), 2, 1);                                                                  //упаковка созданного коэф-та c

//отсылка коэф-тов на другие узлы для решения кв. ур-ия

                                     pvm_send(tids[i], msgtype_master_data);                                                                  //присваивает сообщению идентификатор msgtype_master_data и посылает сообщение задаче с идентификатором tids[i], т.е. всем что есть в массиве

                     }

                                                                                          //создание коэф-тов для решения ур-ия на этом узле

                   a = ((long double) rand() /((long double)RAND_MAX+1.0));

                   b = ((long double) rand() /((long double)RAND_MAX+1.0));

                   c = ((long double) rand() /((long double)RAND_MAX+1.0));

                                                                                          //решает кв.ур-ие с одними и теми же а,b,c на главном узле

                   for(k = 0; k < N; k++)

                     {

                             raschet(a, b, c);                                                                  //посылает к решению кв.ур-ия

                     }

                                                                                          //получение решений с локальных узлов

                   for(i = 0; i < nslaves; i++)

                     {

                             pvm_recv(-1, msgtype_slave_data);                                                                  //получение решения с друго узла

                              pvm_upkdouble(x, 2, 1);                                                                  //распаковка полученного решения

                     }

           }

                                                                                  //сумматор времени процессора, затр. на решение зад. на кластере

           for(i = 0; i < nslaves; i++)

           {

           pvm_recv(-1, msgtype_slave_time);                                                                  //ожидает сообщения с иденификатором msgtype_slave_time от задачи с идентификатором -1

           pvm_upkdouble(&time_slave_ci, 1, 1);                                                                  //распакует принятые данные из массива с указателем &time_slave_ci длинной 1 с 1 элементом указанного типа в одном элементе массива

                                                                                  //общее время решения ур-ия на всех локальных узлах кластера

           time_cpu_master_c += time_slave_ci;                                                                  //суммирует время решения задачи на других машинах

           }

           clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_c);                                                                  //окончание счета процессорного времени на решение задачи

           clock_gettime(CLOCK_MONOTONIC, &end_l);                                                                  //конец точного измерения тактов процессора

                                                                                  //общее процессорное время решения задачи на кластере

           total_time_cpu_c = timespecDiff(&end_c, &start_c) + time_cpu_master_c;                                                                  //сумма времен затраченных на решение задачи на кластере

           time_global_master_l = timespecDiff(&end_l, &start_l);                                                                  //сумма тактов процессора на решение задачи на главной машине

                                                                  //печать в stdout общего процессорного времени решения задачи на всем кластере и тактов процессора на главной машине.

printf("%20.9f\t%20.9f\n", time_global_master_l, total_time_cpu_c);

   }

                                                                          //2 часть программы для локального узла

   else

   {

           mytid = pvm_mytid();                                                                  //регистрирует процесс в PVM, возвращает TID текущего процесса

           clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ci);                                                                  //начало отсчета времени работы процессора

           master = pvm_parent();                                                                  //узнает идентификатор родительской задачи

           pvm_recv(master, msgtype_argv);                                                                  //ожидает поступления сообщения с идентификатором msgtype_argv от задачи с идентификатором master

           pvm_upklong(&N, 1, 1);                                                                  //распаковка N

           pvm_upklong(&np, 1, 1);                                                                  //распаковка np

           for(j = 0; j < np; j++)

           {

                   pvm_recv(master, msgtype_master_data);                                                                  //ожидает поступления сообщения с идентификатором msgtype_master_data от задачи с идентификатором master

                   pvm_upklong((long int *)(&a), 2, 1);                                                                  //распаковка

                   pvm_upklong((long int *)(&b), 2, 1);                                                                  //распаковка

                   pvm_upklong((long int *)(&c), 2, 1);                                                                  //распаковка

                   for(k = 0; k < N; k++)

                   {

                           raschet(a, b, c);                                                                  //посылает к решению кв.ур-ия

                   }

                   pvm_initsend(PvmDataInPlace);                                                                  //инициализация буфера пересылки без кодировки для отправки решения

                   pvm_pkdouble(x, 2, 1);                                                                  //упаковка решения кв.ур-ия

//отсылка решений на главный узел

                   pvm_send(master, msgtype_slave_data);                                                                  //присваивает сообщению идентификатор msgtype_slave_data и посылает сообщение задаче с идентификатором master

           }

           clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ci);                                                                  //конец отсчета времени работы процессора

           time_slave_ci = timespecDiff(&end_ci, &start_ci);                                                                  //время работы процессора на локальном узле

           pvm_initsend(PvmDataInPlace);                                                                  //инициализация буфера пересылки без кодировки

           pvm_pkdouble(&time_slave_ci, 1, 1);                                                                  //упаковка

                                                                                  //отсылка времени работы процессора на решение ур-ия на локальном узле

           pvm_send(master, msgtype_slave_time);                                                                  //присваивает сообщению идентификатор msgtype_slave_time и посылает сообщение задаче с идентификатором master

   }

pvm_exit();                                                                  //завершение пользование услугами PVM

return 0;

}

                                                                  //алгоритм решения квадратного уравнения, коэффициентами которого являются случайные вещественные числа

void raschet(double a, double b, double c)

{

   double D;

   D = b*b - 4*a*c;

   if(D == 0)

   {

           x[0] = x[1] = -b/(a);

   }

   if(D < 0.)

   {

           double t = 1/(2.*a);

           x[0] = -b*t; x[1] = sqrt(-1*D)*t;

   }

     if(D > 0.)

   {

           x[0] = (-b + sqrt(D))/(a*2.); x[1] = (-b - sqrt(D))/(a*2.);

   }

}

Текст программы, для имитационной модели метода Монте-Карло:

//вывод число хостов, число задач запущенных, второй аргумент, первый аргумент,

#include <stdio.h>

#include <stdlib.h>

#include <stdint.h>

#include <pvm3.h>

#include <math.h>

#include <time.h>

double timespecDiff(struct timespec *timeA_p, struct timespec *timeB_p)

{

return ((double)(timeA_p->tv_sec) + ((double)(timeA_p->tv_nsec))/1000000000) -

    ((double)(timeB_p->tv_sec) + ((double)(timeB_p->tv_nsec))/1000000000);

}

int main(int argc, char *argv[])

{

int mytid;           /* my task id */

   int tids[100];                                           /* slave task ids */

int nslaves, i, msgtype, nhosts, narch, master;

/*unsigned*/ long int N, S, Si, nN, nH, np;

long double Pi;

long double PiTrue = 4.0 * ((long double)atan(1.0));

long int mk(unsigned long int);

double hostcputime, /*hostlocaltime,*/ timeElapsed_ci, /*timeElapsed_li,*/ timeElapsed_c, timeElapsed_l;

struct pvmhostinfo *hostp;

struct timespec start_c, start_l, end_l, end_c, start_ci,/* start_li, end_li,*/ end_ci;

 

clock_gettime(CLOCK_MONOTONIC, &start_l);

clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_c);

mytid = pvm_mytid();/*tid master*/

pvm_setopt(PvmRoute, PvmRouteDirect);//``включение'' прямолинейной маршрутизации между задачами PVM

srand((unsigned)time(NULL));

if(pvm_parent() == PvmNoParent)

{

   pvm_config(&nhosts, &narch, &hostp);

   sscanf(argv[2],"%lu",&np);

   sscanf(argv[1],"%lu",&N);

   nslaves = np * nhosts - 1;

   //число хостов, число задач запущенных на хосте, второй аргумент, первый аргумент

printf("%d\t%d\t%lu\t%lu\t", nhosts, (nslaves+1), np, N);

   nslaves=pvm_spawn(&argv[0][0], (char**)0, 0, "", nslaves, tids);

   nN = N / (nslaves + 1);

   nH = N - nslaves * nN;

   //nH, nN,

printf("%ld\t%ld\t", nH, nN);

   pvm_initsend(PvmDataInPlace);

   pvm_pklong(&nN, 1, 1);

   pvm_mcast(tids, nslaves, 0);

   S = mk(nH);

   msgtype = 1;

   for(i=0; i<nslaves; i++)

   {

           pvm_recv(-1, msgtype);

           pvm_upklong(&Si, 1, 1);

           pvm_upkdouble(&timeElapsed_ci, 1, 1);

           //pvm_upkdouble(&timeElapsed_li, 1, 1);

           S += Si;

           hostcputime += timeElapsed_ci;

           //hostlocaltime += timeElapsed_li;

   }

   Pi = 4.0 * ((long double)S) / ((long double)N);

   clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_c);

   clock_gettime(CLOCK_MONOTONIC, &end_l);

   timeElapsed_c = timespecDiff(&end_c, &start_c);

   timeElapsed_l = timespecDiff(&end_l, &start_l);

   //расчетное значение ПИ, погрешность вычисления

printf("%20.18Lf\t%7.1Le\t",Pi,((long double)fabs(Pi-PiTrue)));

   //время астронамическое, время процессорное

printf("%20.9f\t%20.9f\n", timeElapsed_l, (timeElapsed_c + hostcputime));

}

else  

 {

   clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_ci);

   msgtype = 0;

   pvm_recv(-1, msgtype);

   pvm_upklong(&nN, 1, 1);

   Si = mk(nN);

   clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_ci);

   timeElapsed_ci = timespecDiff(&end_ci, &start_ci);

   pvm_initsend(PvmDataInPlace);

   pvm_pklong(&Si, 1, 1);

   pvm_pkdouble(&timeElapsed_ci, 1, 1);

   //pvm_pkdouble(&timeElapsed_li, 1, 1);

   msgtype = 1;

   master = pvm_parent();

   pvm_send(master, msgtype);

}

pvm_exit();

}

long int mk(unsigned long int n)

{

unsigned long int i;

long int Sum;

long double x, y;

for(i = 0, Sum = 0; i < n; i++)

{

   x = ((long double) rand() /((long double)RAND_MAX+1.0));

   y = ((long double) rand() /((long double)RAND_MAX+1.0));

   if((x*x + y*y) <= 1.0) Sum++;

}

return Sum;}



Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: