LCOV - code coverage report
Current view: top level - builds/barbot/Cosmos/src/ModelGenerator - server.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 122 159 76.7 %
Date: 2021-06-16 15:43:28 Functions: 12 13 92.3 %

          Line data    Source code
       1             : /*******************************************************************************
       2             :  *                                                                             *
       3             :  * Cosmos:(C)oncept et (O)utils (S)tatistique pour les (Mo)deles               *
       4             :  * (S)tochastiques                                                             *
       5             :  *                                                                             *
       6             :  * Copyright (C) 2009-2012 LSV & LACL                                          *
       7             :  * Authors: Paolo Ballarini BenoƮt Barbot & Hilal Djafri                       *
       8             :  * Website: http://www.lsv.ens-cachan.fr/Software/cosmos                       *
       9             :  *                                                                             *
      10             :  * This program is free software; you can redistribute it and/or modify        *
      11             :  * it under the terms of the GNU General Public License as published by        *
      12             :  * the Free Software Foundation; either version 3 of the License, or           *
      13             :  * (at your option) any later version.                                         *
      14             :  *                                                                             *
      15             :  * This program is distributed in the hope that it will be useful,             *
      16             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of              *
      17             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
      18             :  * GNU General Public License for more details.                                *
      19             :  *                                                                             *
      20             :  * You should have received a copy of the GNU General Public License along     *
      21             :  * with this program; if not, write to the Free Software Foundation, Inc.,     *
      22             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.                 *
      23             :  *******************************************************************************
      24             :  */
      25             : 
      26             : /**
      27             :  * \file server.cpp
      28             :  * This file contain the implementation of a server waiting for
      29             :  * The simulators to give him result and aggregate them.
      30             :  * Most of this file is C code.
      31             :  */
      32             : 
      33             : 
      34             : #include <string>
      35             : #include <stdlib.h>
      36             : #include <stdio.h>
      37             : #include <sstream>
      38             : #include <algorithm>
      39             : #include <iostream>
      40             : #include <vector>
      41             : #include <sys/select.h>
      42             : #include <sys/types.h>
      43             : #include <sys/ioctl.h>
      44             : #include <sys/resource.h>
      45             : #include <sys/time.h>
      46             : #include <sys/wait.h>
      47             : #include <fstream>
      48             : #include <unistd.h>
      49             : #include <signal.h>
      50             : #include <cstdlib>
      51             : #include <errno.h>
      52             : #include <algorithm>
      53             : #include <err.h>
      54             : #include <assert.h>
      55             : #include <random>
      56             : 
      57             : #include "../Simulator/BatchR.hpp"
      58             : #include "result.hpp"
      59             : #include "server.hpp"
      60             : 
      61             : using namespace std;
      62             : 
      63             : //! A list of file descriptor for the select system call.
      64             : fd_set client_list;
      65             : 
      66             : //! A vector of FILE containing the stdout of each simulator.
      67          35 : vector<FILE*> clientstream;
      68             : 
      69             : //! A vector of PID of the simulators
      70          35 : vector<pid_t> clientPID;
      71             : 
      72             : 
      73             : 
      74             : //! The maximal index of file descriptor in client_list.
      75             : int max_client=0 ;
      76             : 
      77             : 
      78             : //! Boolean indicating if the simulation should continue.
      79             : bool continueSelect=false;
      80             : 
      81           0 : void signalHandlerIgn(int){
      82             :     //cerr << "Receive signal: "<< signum << endl;
      83           0 : };
      84             : 
      85          96 : void signalHandler( int signum )
      86             : {
      87             :     //cerr << "Receive signal: "<< signum << endl;
      88          96 :     switch (signum){
      89             :         case SIGCHLD: {
      90             :             
      91             :             int status;
      92          96 :             pid_t child = wait(&status);
      93             : 
      94          96 :             if(child != -1){
      95           6 :                 if(!WIFEXITED(status)){ //Something to report
      96           0 :                     if(WTERMSIG(status)!=SIGHUP && WTERMSIG(status)!=SIGINT && WTERMSIG(status)!=SIGABRT){ //Normal termination of process
      97           0 :                         if(count(clientPID.begin(),clientPID.end(),child)==0)
      98           0 :                             cerr << "The unknown child "<< child << "Terminated by signal :" << WTERMSIG(status) << endl;
      99             :                         else{
     100           0 :                             if(WIFSIGNALED(status)){
     101           0 :                                 cerr << "Simulator "<< child << "Terminated by signal :" << WTERMSIG(status) << endl;
     102           0 :                                 exit(EXIT_FAILURE);
     103           0 :                             } else if(WIFEXITED(status)){
     104           0 :                                 if(WEXITSTATUS(status) != 130){
     105           0 :                                     cout << "Simulator exit with code " << WEXITSTATUS(status) << endl;
     106             :                                 }
     107             :                             }else {
     108           0 :                                 cerr << "Simulator "<< child << " Crash ! with unknown status "<< status  << endl;
     109             :                             }
     110             :                         }
     111             :                     }
     112             :                 }
     113             :             }
     114          96 :             break;
     115             :         }
     116             :         case SIGINT:
     117           0 :             continueSelect = false;
     118           0 :             break;
     119             :         case SIGPIPE:
     120           0 :             cerr << "receive a sigpipe" <<endl;
     121           0 :             break;
     122             :             
     123             :             
     124             :         default:
     125           0 :             cerr << " Unexpected signal: " << signum << endl;
     126             :     }
     127          96 : }
     128             : 
     129             : /*
     130             :  * Open a child processes retriving both PID and an a pipe
     131             :  * to the standart input of the child.
     132             :  * This function fork and execute the given binary
     133             :  * on the child.
     134             :  * @param bin the path to the binary to execute.
     135             :  * @param argv the list of argument.
     136             :  */
     137          34 : void popenClient(const char* bin, const char *argv[]){
     138          34 :         pid_t pid = 0;
     139             :         int pipefd[2];
     140             :         int pipeerr[2];
     141             :         FILE* output;
     142             :         
     143             :         //create a pipe
     144          34 :         if(pipe(pipefd) !=0  )err(1,"Fail to launch simulator");
     145          34 :         if(pipe(pipeerr) != 0)err(1,"Fail to launch simulator");
     146          34 :         pid = fork(); //fork the process
     147          34 :         if (pid == 0){
     148             :                 //Child.
     149           0 :                 close(pipefd[0]);
     150           0 :                 close(pipeerr[0]);
     151           0 :         if(dup2(pipefd[1], STDOUT_FILENO)<0){
     152           0 :             perror("Fail to redirect stdout");
     153           0 :             exit(EXIT_FAILURE);
     154             :         }
     155             :                 //if(dup2(pipeerr[1], STDERR_FILENO)<0)perror("Fail to redirect stderr");
     156           0 :         if(execvp(bin,(char *const *)argv)<0){
     157           0 :             perror("Fail to lauch the client");
     158           0 :             exit(EXIT_FAILURE);
     159             :         }
     160          34 :         }else if(pid>0){
     161             :                 
     162             :                 //Only parent gets here. Listen to what the tail says
     163          34 :                 close(pipefd[1]);
     164          34 :                 close(pipeerr[1]);
     165             :                 
     166             :                 //open the output of the client.
     167          34 :                 output= fdopen(pipefd[0], "r");
     168             :                 //if(dup2(STDERR_FILENO,pipeerr[0])<0)perror("Fail to redirect stderr");
     169             :                 
     170          34 :                 clientstream.push_back(output);
     171          34 :                 int streamfd = fileno(output);
     172          34 :                 if(streamfd >max_client)max_client = streamfd;
     173          34 :                 clientPID.push_back(pid);
     174             :                 
     175           0 :         }else perror("Fail to fork");
     176          34 : }
     177             : 
     178          34 : inline void pushint(const char *argv[],size_t &argn,size_t v){
     179          34 :         char* s = (char *)malloc(255*sizeof(char));
     180          34 :         sprintf(s, "%zu", v);
     181          34 :         argv[argn] = s;
     182          34 :         argn++;
     183          34 : }
     184             : 
     185             : inline void pushbool(const char *argv[],size_t &argn,bool v){
     186             :         char* s = (char *)malloc(255*sizeof(char));
     187             :         sprintf(s, "%i", v);
     188             :         argv[argn] = s;
     189             :         argn++;
     190             : }
     191             : 
     192             : inline void pushdouble(const char *argv[],size_t &argn,double v){
     193             :         char* s = (char *)malloc(255*sizeof(char));
     194             :         sprintf(s, "%e", v);
     195             :         argv[argn] = s;
     196             :         argn++;
     197             : }
     198             : 
     199             : 
     200          68 : inline void pushstr(const char *argv[],size_t &argn,const char* v){
     201          68 :         char* s = (char *)malloc(255*sizeof(char));
     202          68 :         sprintf(s, "%s", v);
     203          68 :         argv[argn] = s;
     204          68 :         argn++;
     205          68 : }
     206             : 
     207          34 : void freestr(const char *argv[],size_t t){
     208         136 :         for(size_t i =0; i<t;i++)
     209         102 :                 free((void *)argv[i]);
     210          34 : }
     211             : 
     212          31 : void launch_clients(parameters& P){
     213             :     
     214             :     // if seed is zero generate a pseudo random seed.
     215          31 :     if(P.seed==0){
     216             :         timeval t;
     217          31 :         gettimeofday(&t,(struct timezone*)0);
     218             :         //os << " " <<(t.tv_usec + t.tv_sec + getpid()+i);
     219          62 :         std::random_device rd;
     220          31 :         P.seed = rd();
     221             :     }
     222             : 
     223          65 :         for(int i = 0;i<P.Njob;i++){
     224          68 :                 string cmd = P.tmpPath + "/ClientSim";;
     225          34 :                 const char *argv[15] = {0};
     226          34 :                 size_t argn = 0;
     227          34 :                 pushstr(argv, argn, cmd.c_str());
     228          34 :         pushstr(argv,argn,P.tmpPath.c_str());
     229          34 :         pushint(argv,argn,P.seed+i);
     230             :                 
     231          34 :                 if(P.verbose >2){
     232           0 :                         for(size_t i=0; i<argn; i++ )cout << " " << argv[i];
     233           0 :                         cout << endl << endl;
     234             :         }
     235             : 
     236          34 :         popenClient(cmd.c_str(),argv);
     237             :         
     238             :         
     239          34 :         freestr(argv, argn);
     240             : 
     241             :     }
     242             : 
     243          31 : }
     244             : 
     245          62 : void kill_client(){
     246             :     //cout << "Enter kill client" << endl << endl << endl;
     247          93 :     while (!clientPID.empty()){
     248          31 :         if (clientPID.back()!=0)kill(clientPID.back(),SIGHUP);
     249             :         //cerr << "Kill Client " << clientPID.back() << endl;
     250          31 :         clientstream.pop_back();
     251          31 :         clientPID.pop_back();
     252             :     }
     253             :     //cerr << "Quit kill client" << endl << endl << endl << endl << endl;
     254          31 : }
     255             : 
     256          31 : void wait_client(){
     257          31 :     pid_t child= 1;
     258         149 :     while (child != -1) {
     259             :                 int termstat;
     260          59 :                 child = wait(&termstat);
     261             :         }
     262             :         
     263          31 : }
     264             : 
     265         236 : void makeselectlist(void){
     266         236 :     FD_ZERO(&client_list);
     267         490 :     for(size_t it = 0;it < clientstream.size(); it++){
     268         254 :         int fl = fileno(clientstream[it]);
     269         254 :         FD_SET(fl,&client_list);
     270             :     }
     271         236 : }
     272             : 
     273             : /**
     274             :  * This function launches a set of simulators and stop them once
     275             :  * The precision criterion is reach.
     276             :  */
     277          31 : void launchServer(parameters& P){
     278             :     
     279          31 :     signal(SIGCHLD , signalHandler);
     280          31 :     signal(SIGINT, signalHandler);
     281          31 :     signal(SIGPIPE, signalHandler);
     282             :     
     283             :     //Init result
     284          62 :     result Result;
     285             : 
     286             :     //Try to read previous batch
     287          31 :     if(P.reuse){
     288           0 :         FILE* intraj = fopen((P.tmpPath+"/saveTraj").c_str(),"r");
     289           0 :         if(intraj != NULL){
     290           0 :             BatchR batchResult(P.nbAlgebraic,P.nbQualitatif);
     291           0 :             batchResult.inputR(intraj);
     292           0 :             Result.addBatch(batchResult);
     293           0 :             cout << Result.MeanM2.I << " Previous Trajectories found and loaded" << endl;
     294             :         }
     295             :     }
     296             : 
     297          31 :     if(P.verbose>0)cout << "START SIMULATION ..." << endl<< endl << endl << endl;
     298             : 
     299             :     //Launch a set of simulators
     300          31 :     launch_clients(P);
     301             :     //Make a list of file system for polling
     302             :     
     303             :     sigset_t blockingset;
     304          31 :     sigfillset(&blockingset);
     305             :     
     306          31 :         continueSelect = true;
     307             :     //Check if the simulation should continue.
     308         503 :     while(Result.continueSim() && !clientstream.empty() && continueSelect){
     309         236 :         makeselectlist();
     310             :         //wait for a simulator to return some result
     311         236 :         if(pselect(max_client+1, &client_list, NULL, NULL, NULL,&blockingset) == -1){
     312           0 :             perror("Server-select() error!");
     313           0 :             exit(EXIT_FAILURE);
     314             :         }
     315             :                 //Iterate over the simultor to check wich one has some results.
     316         490 :         for(size_t it = 0;it < clientstream.size() ;it++){
     317         254 :             if(FD_ISSET(fileno(clientstream[it]),  &client_list)){
     318             :                 //aggregate the new result to the total result
     319         472 :                 BatchR batchResult(P.nbAlgebraic, P.nbQualitatif);
     320         236 :                 if(batchResult.inputR(clientstream[it])){
     321             :                                         //batchResult.print();
     322         233 :                                         Result.addBatch(batchResult);
     323             :                                         //If required output the progress of the computation.
     324         233 :                                         if((P.verbose>0 || P.alligatorMode) && P.computeStateSpace==0 )
     325         232 :                         Result.printProgress();
     326             :                                 } else {
     327             :                                         //The batch result was not complete.
     328             :                                         //If the simulator was kill by the server it is OK otherwise
     329             :                                         //it is a problem.
     330           3 :                                         if(P.verbose>2) cerr << "Warning uncomplete or ill formed Batch Result"<<endl;
     331           3 :                                         if(feof( clientstream[it] )!=0){
     332           3 :                                                 if(P.verbose>2)cerr << "Deconnection Simulator:" << clientPID[it] << endl;
     333           3 :                                                 clientstream.erase(clientstream.begin() + it);
     334           3 :                                                 clientPID.erase(clientPID.begin() + it);
     335             :                                         }
     336             :                                 }
     337             :                         }
     338             :         }
     339             : 
     340             :     }
     341             :     /*signal(SIGPIPE, signalHandler);*/
     342             : 
     343             :     //Kill all the simulator
     344          31 :     kill_client();
     345             : 
     346             :         //Output all the results
     347          31 :     Result.stopclock();
     348          31 :     if(P.verbose>0){
     349          31 :         Result.printCompactResult();
     350          31 :         cout<< endl;
     351             :     }
     352             : 
     353          31 :     if(P.tmpStatus != 0){
     354          62 :         ofstream savetraj(P.tmpPath+"/saveTraj");
     355          31 :         Result.MeanM2.outputR(savetraj);
     356             :     }
     357             : 
     358             :         //use gnuplot
     359          31 :         if(P.dataPDFCDF.length()>0)Result.outputCDFPDF(P.dataPDFCDF);
     360             :         //if(P.alligatorMode)
     361          31 :     signal(SIGCHLD, signalHandlerIgn);
     362          31 :         Result.printGnuplot();
     363          31 :     signal(SIGCHLD, signalHandler);
     364             : 
     365          31 :     Result.close_gnuplot();
     366             :     
     367          31 :         wait_client();
     368             :     
     369          31 :         if(P.alligatorMode){
     370           0 :                 Result.printAlligator();
     371             :         } else{
     372          31 :         if(P.verbose>1)Result.print(cout);
     373             :         }
     374             :         
     375          31 :         size_t lastslash = P.PathLha.find_last_of("/");
     376          31 :         if(lastslash==string::npos)lastslash= -1;
     377          31 :         size_t lastdot = P.PathLha.find_last_of(".");
     378          62 :     string fn = "Result_" + P.PathLha.substr(lastslash+1,lastdot - lastslash-1 );
     379          31 :     fn.append(".res");
     380          31 :     Result.printResultFile(fn);
     381          31 :         Result.printResultFile("Result.res");
     382             :     
     383         136 : }

Generated by: LCOV version 1.13