Home - Templet-language/mpiruntime GitHub Wiki

Дамир,

Предлагаю внести ещё одно упрощение в текущую реализацию с MPI. Мы предполагали следующую схему выполения:

int main(int argc, char*argv[])
{
   engine e(argc,argv); // дочерние процессы выполняют код до этой команды
   // конструируем процессы
   prc1 p1=e.prc1();
   prc2 p2=e.prc2();
   .................
   // связываем их
   p1.port1(p2.port2());
   .................
   // инициализируем процессы
   p1.data="что-то";
   p2.data="ещё что-то";
   .................
   // запускаем вычисления
   e.run();
   // выводим результаты
   cout << p1.data;
   cout << p2.data;
}

Упрощение следующее. Выделяем явно секции построения графа программы и инициализации данных. Предполагаем, что граф программы никак не зависит от входных данных программы. Например, так:

int main(int argc, char*argv[])
{
   engine e(argc,argv);
   // конструируем процессы
   prc1 p1=e.prc1();
   prc2 p2=e.prc2();
   .................
   // связываем их
   p1.port1(p2.port2());
   .................
   
   // даём команду отображения графа алгоритма на ВС
   // дочерние процессы выполняют код только до этой команды
   e.map();

   // а теперь инициализируем процессы
   p1.data="что-то";
   p2.data="ещё что-то";
   .................
   // запускаем вычисления
   e.run();
   // выводим результаты
   cout << p1.data;
   cout << p2.data;
}

В данном случае не требуется размножать информацию о графе программы и управлять сборкой графа на удалённых узлах. Для примера Sin2(x)+Cos2(x) код может выглядеть так:

int main(int argc, char*argv[])
{
   engine e(argc,argv);
   
   // конструируем процессы
   Parent p(e);
   Child  ch1(e),ch2(e);
   
   // связываем их
   ch1.p(p.p1());
   ch2.p(p.p2());
   
   // назначаем процессы на узлы MPI
   p.at(0); ch1.at(1); ch2.at(2);
   
   // на этом часть, выполняющаяся на всех узлах закончена
   // даём команду отображения графа алгоритма на ВС
   // дочерние процессы выполняют код только до этой команды
   e.map();

   // а теперь инициализируем процессы
   cin >> x;
   
   // запускаем вычисления
   p.init();
   e.run();

   // выводим результат
   cout << "Sin2(x)+Cos2(x)=" << one;
 }

Примерный алгоритм работы вызова e.map();

 if(rank текущего процесса == 0){
     for(актор : все акторы программы){
        if(актор назначен на процесс с rank!=0)  отправить актор на его процесс;
     }
 }
 else{
     for(актор : акторы, назначенные на текущий процесс) принять актор;

     for(){
        обрабатывать сообщения;
        if(сообщений больше нет) break;
     }

     for(актор : акторы, назначенные на текущий процесс)
         выслать актор мастер-процессу;

     закрыть процесс MPI, вызвав MPI_Finalize();
     return 0; 
 }

Примерный алгоритм работы вызова e.run();

 for(){
        обрабатывать сообщения;
        if(сообщений больше нет) break;
 }
 
 разослать всем процессам команду "переслать свои акторы мастер-процессу";
 
 for(актор : все акторы программы){
        if(актор назначен на процесс rank!=0)  принять актор с данного процесса;
 }

 закрыть процесс MPI, вызвав MPI_Finalize();