/******************************************************************* * * DESCRIPTION: class ParallelMainSimulator * * AUTHOR: Ezequiel Glinsky * Revised By: Qi (Jacky) Liu * * Revision Date: Sept. 2005 *******************************************************************/ /** include files **/ #include #include #include #include "parsimu.h" // base header #include "stdaload.h" #include "ini.h" // class Ini #include "pmodeladm.h" // class ParallelModelAdm #include "strutil.h" // lowerCase, str2Int #include "coupled.h" // class Coupled #include "zone.h" // class zone #include "cellpartition.h" // class CellPartition #include "flatcoup.h" // class FlatCoupledCell #include "tdcell.h" // #include "idcell.h" // #include "statevars.h" #include "JackyDebugStream.h" #ifdef MPI #include "mpi.h" // MPI_Routines #endif //#ifdef JACKY_DEBUG #include "pcoordin.h" //ParallelCoordinator (DependantList) #include "pmcoordin.h" //ParallelMCoordinator (slaves) #include "pncoord.h" //ParallelNodeCoordinator #include "pfcoord.h" #include #include //for getpid() #include //for getpid() gethostname() class JackyDebugStream; //#endif //end JACKY_DEBUG //define SIMUNTIL. Set the lp simulation stop time to Infinity. //The actual simulation stop time will be controlled by the Parallel Root //processor. const VTime LogicalProcess::SIMUNTIL = PINFINITY; //Allocate static variables ParallelMainSimulator *ParallelMainSimulator::instance(NULL); //getLineOnFile int getLineOnFile(FILE *fileIn, char *linea); /******************************************************************* * Function Name: Constructor ********************************************************************/ ParallelMainSimulator::ParallelMainSimulator() : #ifdef JACKY_UNIQUE_LOG //[2006-04-26] ================================= localNC( NULL ), //the address of the local NC is initialized to NULL #endif //end JACKY_UNIQUE_LOG //[2006-04-26] =========================== separator( '@' ) , componentLabel( "components" ) , inPortsLabel("in") , outPortsLabel("out") , linksLabel("link") #if defined(JACKY_INFREQ_STATEMANAGER) && defined(INFREQSTATEMANAGER) //[2006-03-20] ----------------------------- #if defined(JACKY_FOSSIL_COLLECTION_STRATEGY_A) //[2006-03-26] , topHasOutputPorts(false) //by default, we suppose TOP model has no output ports #endif //end JACKY_FOSSIL_COLLECTION_STRATEGY_A [2006-03-26] #endif // end JACKY_INFREQ_STATEMANAGER && INFREQSTATEMANAGER //[2006-03-20] ------------------------------------- , sloader( NULL ) , vDebugStream ( NULL ) { registerNewAtomics(); } /******************************************************************* * Function Name: Destructor ********************************************************************/ ParallelMainSimulator::~ParallelMainSimulator() { //Release acquired memory if ( vDebugStream ) { (*vDebugStream) << flush; delete vDebugStream; } } /******************************************************************* * Function Name: Instance ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::Instance() { if( !instance ) { instance = new ParallelMainSimulator(); } return *instance; } /******************************************************************* * Function Name: run ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::run() { //#ifdef JACKY_STATISTICS //[2006-04-02] // // BasicTimeWarp::initializationWatch.start(); // //#endif //end JACKY_STATISTICS //[2006-04-02] if( !loader() ) { MException e( "The ParallelMainSimulator loader not found!" ) ; e.addText( "The loader must be seted before running the simulation." ) ; MTHROW( e ) ; } //Open the comm chanel to get the machine ID and //the command line parameters (if machine is not start up machine). //Jacky: //this invokes openComm() in StandAloneLoader, which calls physicalCommInit() and physicalCommGetId() //in CommPhyMPI.cc. //physicalCommInit() -> calls physicalInit() -> calls MPI_Init() & MPI_Buffer_attach() //physicalCommGetId() -> calls physicalGetId() -> calls MPI_Comm_rank(MPI_COMM_WORLD, &id) loader()->openComm(); #ifdef JACKY_DEBUG //now the MPI is set up and machineId is available //for debugging cd++ on multiple machines, we need to attach GDB to the //process id of this program on each machine. let's print out the //process id on each machine and sleep for a while int tempMachineId = loader()->getMachineID(); char hostname[40]; if(gethostname(hostname,40) == -1){ cerr << "Failed to get host name!!!" << endl; } sleep(tempMachineId); //sleep different time to show the processId separately cerr << "LP[" << tempMachineId << "] on " << hostname << " pid = " << (int)getpid() << endl; cerr << endl; //if(tempMachineId == 0){ // cerr << "Sleep 1 sconds, please attach GDB to these processID now..." << endl; //} sleep(2); cerr << "PCD resumed!!!" << endl; #endif #ifndef JACKY_DEBUG char hostname[40]; if(gethostname(hostname,40) == -1){ cerr << "Failed to get host name!!!" << endl; } cerr << "\tRun on ->" << hostname << endl; #endif //Read the command line arguments. loader()->loadData(); ostream& out = debugStream(); //Load all the models and the model partition. loadModels( loader()->modelsStream(), loader()->partitionStream(), loader()->printParserInfo() ); //Display the model partition showModelPartition(out); #ifdef JACKY_DEBUG //$$$jacky: 2005-08-15 print out the ModelPartition to the debug file ostream& jacky_os = JackyDebugStream::Instance().Stream(); showModelPartition(jacky_os); #endif //If a log file is to be created and this is the starting machine, save log file info //for drawlog if ( getMachineID() == 0 && logName() != "/dev/null" ) { fstream logInfo ( logName().c_str() , ios::out ); showLogInfo(logInfo); #ifdef JACKY_DEBUG jacky_os << "----------------------- logName = " << logName() << " -----------------" << endl; showLogInfo(jacky_os); #endif } // Flatten the links of all models // Show on the screen all the loaded links //cerr << "[" << getMachineID() << "] BEFORE FLATTENING..." << endl; //cerr << "[" << getMachineID() << "] INPUT PORTS" << endl; // debugInputPorts(); //cerr << "[" << getMachineID() << "] OUTPUT PORTS" << endl; // debugOutputPorts(); //#ifdef JACKY_DEBUG // jacky_os << "************* Before flattenLinks() *****************" << endl; //#endif // debugFlattenedLinks(); // flattenLinks(); // Flatten the Links //cerr << "[" << getMachineID() << "] AFTER FLATTENING..." << endl; //#ifdef JACKY_DEBUG // jacky_os << "************* After flattenLinks() *****************" << endl; //#endif // debugFlattenedLinks(); // Show the final state of the links //Set up de Warped logical process. This will create all the local processors. setUpLogicalProcess(); SingleParallelProcessorAdmin::Instance().showProcessors(out); //The root processor will run on machine with id 0 (starting machine) //If this is machine with Id 0, then setup the Root processor out << "All objects have been registered!" << endl << flush; //Tell the LP that all processors have been registered //This will also initialize all the processor current state!!! lp->allRegistered(); //jacky: this will // 1> call allocateState() in each ParallelProcessor, set the initial state as the current state // set the initial state's dirty=false, and lVT=ZERO // 2> call initialize() in each ParallelProcessors // 3> call saveState() for each processor (simuObj) // -> set the initial state's outputPos to the tail of the outputQ // set the initial state's myLastOutput=true // 3'>call stateManager's saveState() -> save a clone of the initial state to the end of the stateQ // 4> call LOCAL simObj's clearInitState() -> set the correct values in the current state // -> set current state's outputPos to the tail of the outputQ (again?!) // set current state's myLastOutput=true (again?!) #ifdef JACKY_DEBUG //$$$jacky: at this time, all processors are created. //let's print out the simArray on each LP printSimArray(jacky_os); //let's print out the models printModels(jacky_os); //let's print out the ProcessorDB in the ParallelProcessorAdmin printProcessors(jacky_os); //$$$jacky end #endif #ifndef JACKY_RB_ZERO //Nov. 7, 2005 //JACKY Note: this function has been moved into the LogicalProcess::allRegistered() //Call afterInitialize for all local Models. out << "After Initialize...." << flush; afterInitialize(); //jacky: call afterProcessorInitialize() func for models that have a LOCAL processor on this machine out << "OK" << endl << flush; #endif //JACKY_RB_ZERO #ifndef JACKY_REVISION //original version (loading external events into the ParallelRoot on machine 0) if (getMachineID() == 0 ) { //on machine 0 out << "Loading external events..." << endl; loadExternalEvents( loader()->eventsStream() ); //load external events given in .EV file to the ParallelRoot out << "Setting stop time..." << endl; ParallelRoot::Instance().stopTime( loader()->stopTime() ); // set stopTime in ParallelRoot ParallelRoot::Instance().rootSimulate(); //jacky: this version will send (I) msgs to the top model (ParallelMCoordinator) and all NCs } #else //this is my new version for loading external events into the NCs //Jacky: The external events will be loaded into NCs (not into the ParallelRoot) // The ParallelRoot simply sends (I) to all NCs to start the simulation out << "[" << getMachineID() << "] Loading external events into the NC..." << endl; //cerr << "[" << getMachineID() << "] Loading external events into NC" // << nodeCoordinatorsList[ParallelMainSimulator::Instance().getMachineID()] // <<"..." << endl; loadExternalEvents( loader()->eventsStream() ); //load external events into NC on each machine, and sort the events //cerr << "Loading external events in NC" // << nodeCoordinatorsList[ParallelMainSimulator::Instance().getMachineID()] // << " done!" << endl; if (getMachineID() == 0 ) { //on machine 0 //Jacky Note: the stopTime has been loaded into NCs in their initialize() functions ParallelRoot::Instance().rootSimulate(); //jacky: this will send I msg to all NCs (msg is no longer sent to the ParallelMCoordinator for the TOP model) } #endif //end JACKY_REVISION #ifdef JACKY_DEBUG //let's chech the NCList and FCList in the ParallelMainSimulator printNCList(jacky_os); printFCList(jacky_os); //let's print out each coordinator's dependantList printDependantList(jacky_os); //let's print out the slaves for each Master coordinator printSlaves(jacky_os); //check the external events in NC jacky_os << "----------------------------- external events in NC: ---------------------------" << endl; this->showEvents( this->getEventsInNC(), jacky_os); jacky_os << "--------------------------------------------------------------------------------" << endl; //show all the input & output ports in all models, help us to find whether a Y msg is going to the TOP for output //this will output to another file called "model_ports.output" //since the ModelDB is the same on all machines, we only create this file on machine0 if(getMachineID() == 0){ string modelPortFile = "model_ports.output"; fstream modelPortStream(modelPortFile.c_str(), ios::out); modelPortStream << "------------------ input & output ports for all models -------------------------------" << endl; ParallelModelAdmin::ModelDB models = SingleParallelModelAdm::Instance().models(); //hash_map ParallelModelAdmin::ModelDB::const_iterator model_it; PortList::const_iterator port_it; for(model_it = models.begin(); model_it != models.end(); model_it++){ //for each model, print out its inputPorts() & outputPorts() PortList // map Model* pmodel = model_it->second; PortList inputs = pmodel->inputPorts(); PortList outputs = pmodel->outputPorts(); modelPortStream << endl << "Model: " << pmodel->description() << endl << flush; modelPortStream << "\tInput Ports: " << endl; for(port_it = inputs.begin(); port_it != inputs.end(); port_it++){ modelPortStream << "\t\t" << port_it->second->name() << "[" << port_it->first << "] "; } modelPortStream << endl << flush; modelPortStream << "\tOutput Ports: " << endl; for(port_it = outputs.begin(); port_it != outputs.end(); port_it++){ modelPortStream << "\t\t" << port_it->second->name() << "[" << port_it->first << "] "; } modelPortStream << endl << flush; } modelPortStream << "------------------ All I/O ports for all Models printed -------------------------------" << endl << flush; } //let's print out the influenceList for allports jacky_os << endl << "-----In parsimu::run(), just before the simulation starts, ports' influenceLists are: ------" << endl; InfluenceList::const_iterator influList_it; PortList::const_iterator port_it; for(port_it = allPorts().begin(); port_it != allPorts().end(); port_it++){ Port* ptr = port_it->second; //get a Port* InfluenceList influList = ptr->influences(); //the influenceList for the port jacky_os << "Port: " << ptr->name() << "[" << ptr->id() << "]" << "@" << (ptr->model()).asString() << " influuenceList =>" << endl; for(influList_it = influList.begin(); influList_it != influList.end(); influList_it++){ jacky_os << "\t" << (*influList_it)->name() << "[" << (*influList_it)->id() << "]" << "@" << ((*influList_it)->model()).asString() << " "; } jacky_os << endl << flush; } jacky_os << "------------------- influenceLists for all ports printed ------------------------" << endl << endl; //cout << "Machine[" << loader()->getMachineID() << "] starts to call LP::simulate()!" << endl; #endif //end JACKY_DEBUG //#ifdef JACKY_STATISTICS //[2006-04-02] // // BasicTimeWarp::initializationWatch.stop(); // BasicTimeWarp::initializationTime += BasicTimeWarp::initializationWatch.elapsed(); // //#endif //end JACKY_STATISTICS //[2006-04-02] #ifndef JACKY_REVISION //originally, the actual stopTime is controlled in ParallelRoot //Start the simulation using the default SIMUNTIL = VTime::Inf lp->simulate(); #else //Jacky: give the stopTime to the LP lp->simulate( loader()->stopTime() ); #endif //JACKY_REVISION // Results (do not confuse with log file) are only written to //the starting machine if (getMachineID() == 0 ) loader()->writeResults(); delete lp; //When the lp is deleted, the Comm Chanel is closed return *this; } /******************************************************************* * Function Name: loadModels ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadModels( istream &file, istream &pfile, bool printParserInfo ) { ini.parse( file ); pini.parse( pfile ); //Model partition file //Create Root Model and register its processor Id //The root will run in machine 0 Model &root(SingleParallelModelAdm::Instance().newRoot()); root.addMachine(0); root.setMachineProcId(0, ParallelProcessorAdmin::rootId); //Create top model. Coupled &top(SingleParallelModelAdm::Instance().newCoupled( "top" )); loadModel( top, printParserInfo ); if ( top.isLocalMaster() ) top.parentId(SingleParallelProcessorAdmin::Instance().rootId); else top.parentId( top.masterId()); //NC // -> Create NC Model and register its processor Id, one NC will run on each machine // (getMachineID is associated with each NodeCoordinator's ID) Model &nc(SingleParallelModelAdm::Instance().newNodeCoordinator()); nc.addMachine( getMachineID() ); // Try to review the way of assigning ID to the NodeCoordinator int newNCId = SingleParallelProcessorAdmin::Instance().newId()+getMachineID(); int baseNCId = newNCId - getMachineID(); nc.setMachineProcId(getMachineID(), newNCId); nc.parentId(SingleParallelProcessorAdmin::Instance().rootId); // Store the NC's ID for each Machine // If there are 3 NCs and newID=31: [0]->31, [1]->32, [2]->33 for (int i=0 ; i Create FC Model and register its processor Id, one FC will run on each machine // (getMachineID is associated with each FlatCoordinator's ID) Model &fc(SingleParallelModelAdm::Instance().newFlatCoordinator()); fc.addMachine( getMachineID() ); // Try to review the way of assigning ID to the FlatCoordinator int baseFCId = baseNCId + SingleParallelModelAdm::Instance().totalMachinesCount(); // Determine the new base ID int newFCId = baseFCId + getMachineID(); // new ID for the FC running on this machine // If there are 3 FCs and baseFCId+3=34: [0]->34, [1]->35, [2]->36 fc.setMachineProcId(getMachineID(), newFCId); fc.parentId(newNCId); // The parent is the NC running on the same machine // Store the FC's ID for each Machine for (int i=0 ; ifirst; Port* port = port_it->second; jacky_os << "portId = " << portId << " port = " << port->name() << "@" << (port->model()).asString() << endl; } jacky_os << "------------------------------- all ports printed -------------------------------------" << endl << endl ; #endif // load componentes if( parent.type() == Coupled::cell ) loadCells( static_cast( parent ), printParserInfo ) ; else loadComponents( parent, printParserInfo ) ; // load links loadLinks( parent) ; #ifdef JACKY_DEBUG //$$$jacky: at this time, all links are loaded from the MA file into the ParallelMainSimulator's "allportlinks" //let's print out all these links into the file jacky_os << endl << "-----In parsimu::loadModel(), after loadLinks(" << parent.asString() << "), all links are: ------" << endl; PortLinksList::const_iterator link_it; PortList allports = allPorts(); for(link_it = allPortLinks().begin(); link_it != allPortLinks().end(); link_it++){ PortId sourceId = link_it->first; Port* sourcePort = allports[sourceId]; Port* destPort = link_it->second; jacky_os << "link: " << sourcePort->name() << "[" << sourceId << "]" << "@" << (sourcePort->model()).asString() << " -> " << destPort->name() << "[" << destPort->id() << "]" << "@" << (destPort->model()).asString() << endl << flush; } jacky_os << "------------------------------ all links printed -------------------------------------" << endl << endl; #endif // At this time, the links are created. Now, we load the portInTransitions if ( parent.type() == Coupled::cell) { loadPortInTransitions( static_cast(parent), printParserInfo ) ; loadMachines( static_cast( parent )) ; } else { loadMachines ( parent ); } return *this; } /******************************************************************* * Function Name: loadPorts ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadPorts( Coupled &parent ) { string modelName( lowerCase( parent.description() ) ) ; Ini::IdList::const_iterator cursor ; // ports in if ( ini.exists( modelName, ParallelMainSimulator::inPortsLabel ) ) { const Ini::IdList &ilist( ini.definition( modelName, ParallelMainSimulator::inPortsLabel ) ) ; for( cursor = ilist.begin() ; cursor != ilist.end() ; cursor ++ ) parent.addInputPort( *cursor ) ; } // ports out if( ini.exists( modelName, ParallelMainSimulator::outPortsLabel ) ) { const Ini::IdList &ilist( ini.definition( modelName, ParallelMainSimulator::outPortsLabel ) ) ; for( cursor = ilist.begin() ; cursor != ilist.end() ; cursor ++ ) parent.addOutputPort( *cursor ) ; #if defined(JACKY_INFREQ_STATEMANAGER) && defined(INFREQSTATEMANAGER) //[2006-03-20] ----------------------------- #if defined(JACKY_FOSSIL_COLLECTION_STRATEGY_A) //[2006-03-26] if(modelName == "top"){ //if it is the TOP model, and it has output ports! //set the flag to true topHasOutputPorts = true; } #endif //end JACKY_FOSSIL_COLLECTION_STRATEGY_A [2006-03-26] #endif // end JACKY_INFREQ_STATEMANAGER && INFREQSTATEMANAGER //[2006-03-20] ------------------------------------- } return *this ; } /******************************************************************* * Function Name: loadComponent ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadComponents( Coupled &parent, bool printParserInfo ) { string modelName( lowerCase( parent.description() ) ) ; bool exist = ini.exists( modelName, ParallelMainSimulator::componentLabel ) ; if( !exist ) { MException e( string("Ini: Coupled Model without components!, Label: ") + modelName + " / " + ParallelMainSimulator::componentLabel ) ; MTHROW( e ) ; } else { const Ini::IdList &ilist( ini.definition( modelName, ParallelMainSimulator::componentLabel ) ) ; Ini::IdList::const_iterator cursor ; for( cursor = ilist.begin() ; cursor != ilist.end() ; cursor ++ ) { string mName, atomicType ; bool isAtomic = splitString( *cursor, mName, atomicType, ParallelMainSimulator::separator ) ; if( isAtomic ) { Atomic &model( SingleParallelModelAdm::Instance().newAtomic( atomicType, mName ) ) ; parent.addModel( model ) ; loadMachines ( model ); } else { // es un acoplado Coupled *coupled ; // Si es un acoplado puede ser un CoupledCell if( ini.exists( mName, "type" ) ) { string type( ini.definition( mName, "type" ).front() ) ; if( type == "cell" ) coupled = &( SingleParallelModelAdm::Instance().newCoupledCell( mName ) ) ; else if( type == "flat" ) { MASSERTMSG( false, "This version of CD++ does not support flat cell models." ) ; coupled = &( SingleParallelModelAdm::Instance().newFlatCoupledCell( mName ) ) ; } else MASSERTMSG( false, "Invalid coupled type " + type + "!" ) ; } else coupled = &( SingleParallelModelAdm::Instance().newCoupled( mName ) ) ; parent.addModel( *coupled ) ; loadModel( *coupled, printParserInfo ) ; } } } return *this ; } /******************************************************************* * Function Name: loadMachines ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadMachines( Atomic &atomic ) { #ifdef MPI int machineCount; PIni::MachineList::const_iterator machinesCursor; PIni::IdList::const_iterator modelsCursor; machineCount = 0; for (machinesCursor = (pini.machines()).begin(); machinesCursor != (pini.machines()).end() ; machinesCursor++ ) { //Look for the atomic in this machine for(modelsCursor = (machinesCursor->second).begin(); modelsCursor != (machinesCursor->second).end(); modelsCursor++) { if ( *modelsCursor == atomic.description()) { machineCount++; MASSERTMSG( machineCount == 1, "Ambiguos machine location for atomic: " + atomic.description()); atomic.addMachine( (MachineId) machinesCursor->first); //Set processor Id for the atomic simulator. atomic.setMachineProcId( machinesCursor->first, static_cast< ParallelProcessorAdmin& > ( SingleParallelProcessorAdmin::Instance()).newId()); //cerr << ParallelMainSimulator::Instance().getMachineID() // << ": ParallelMainSimulator::loadMachines(atomic): " << atomic.asString() << " " << endl; }//if }//for modelsCursor } //for machinesCursor //The atomic must be running in one machine MASSERTMSG( machineCount == 1, "No machine has been specified to run atomic: " + atomic.description()); #else atomic.addMachine( 0 ); atomic.setMachineProcId( 0 , static_cast< ParallelProcessorAdmin& > ( SingleParallelProcessorAdmin::Instance()).newId()); #endif return *this; } //loadMachines /******************************************************************* * Function Name: loadMachines ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadMachines( Coupled &coupled ) { Coupled::PModelList::const_iterator childrenCursor; Model *model; for ( childrenCursor = coupled.childModels().begin(); childrenCursor != coupled.childModels().end(); childrenCursor++) { model = *childrenCursor; MachineId mid = model->machineForProcId( model->masterId() ); coupled.addMachine( mid ); //If no processorId has been set, set processor Id. if ( coupled.procInMachine( mid ) == ParallelProcessor::InvalidId ){ coupled.setMachineProcId( mid, SingleParallelProcessorAdmin::Instance().newId()); //cerr << ParallelMainSimulator::Instance().getMachineID() // << ": ParallelMainSimulator::loadMachines(coupled): " << coupled.asString() << " " << endl; } //if } //Now, for each child model, set up the parent/child relationship for ( childrenCursor = coupled.childModels().begin(); childrenCursor != coupled.childModels().end(); childrenCursor++) { // parentId will be set for parallel simulation to the following: // For atomic models: if it is local, parentId = coupled.localProc // if it is not local, it will be the processor of coupled running // on the machine where the atomic is running. // For coupled child models. The same as atomic, but taking only into // account the location of the master processor. model = *childrenCursor; if ( model->isLocalMaster() ) model->parentId( coupled.localProc() ); else model->parentId( coupled.procInMachine (model->machineForProcId( model->masterId() ) ) ); } return *this; } //loadMachines /******************************************************************* * Function Name: loadMachines ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadMachines( CoupledCell &coupledcell ) { //cerr << "ParallelMainSimulator::loadMachines(coupledCell): Loading machines for each coupledCell." << endl; #ifdef MPI //The following must be done: //1. Collect the CellPartitions for all the machines the model will be // running on.As each partition is created, add a machine to the coupled cell // and generate a new procId. //2. For each cell, set the machine where it should run. Verify no // cell will run on two machines and that there is at least one // machine for every cell. // Some cells will not have an AtomicCell instance on the local machine. // For such cells, do not set a local machine. Increment the ProcId also. // This is important to // maintain the consistency of ProcId's on each machine. //1. Let's start collecting the partition information typedef map< MachineId, CellPartition *, less< MachineId > > CellsMap; CellsMap cellsMap; for(PIni::MachineList::const_iterator machines = pini.machines().begin(); machines != pini.machines().end(); machines++ ) { CellPartition *partition = new CellPartition(coupledcell.dimension(), coupledcell.borderWrapped()); //Iterate along the list of models defined for the current machine for (PIni::IdList::const_iterator cursor = machines->second.begin(); cursor != machines->second.end(); cursor++) { string modelName, zone; int index = (*cursor).find( '(' ); if( index >= 0 ) { modelName= (*cursor).substr( 0, index ); zone = (*cursor).substr( index ); if ( modelName == coupledcell.description() ) partition->addLocalZone( zone ); } } //for //Add the cell partition to the cellsMap if( partition->totalElements() > 0 ) { cellsMap[machines->first] = partition; //Create a new ProcId //This has to be done before calling coupledCell->setCellMachine coupledcell.setMachineProcId(machines->first, SingleParallelProcessorAdmin::Instance().newId()); } else { delete partition; } } //2. For each cell, set the machine where it should run CellPosition counter( coupledcell.dimension().dimension(),0); bool overflow = false; while ( !overflow ){ int machineCount = 0; //Get the procId for the cell ProcId procId = SingleParallelProcessorAdmin::Instance().newId(); for( CellsMap::const_iterator cellmap = cellsMap.begin(); cellmap != cellsMap.end(); cellmap++ ) { if( cellmap->second->localCellsInclude( counter )) { machineCount++; MASSERTMSG( machineCount == 1, "Ambiguos machine location for cell: " + counter.print()); //SetCellMachine will also create the parent - child //relationship. coupledcell.setCellMachine( counter, cellmap->first , procId); } } MASSERTMSG( machineCount == 1, "No machine has been speciefied for cell: " + counter.print()); overflow = counter.next( coupledcell.dimension() ); }//while //Now, delele all the cellpartitions that were just created for( CellsMap::const_iterator cellmap = cellsMap.begin(); cellmap != cellsMap.end(); cellmap++ ) delete cellmap->second; #else CellPosition counter( coupledcell.dimension().dimension(),0); bool overflow = false; //Set the machine for the coupled cell model coupledcell.setMachineProcId( 0, SingleParallelProcessorAdmin::Instance().newId()); while ( !overflow ){ //Get the procId for the cell ProcId procId = SingleParallelProcessorAdmin::Instance().newId(); coupledcell.setCellMachine( counter, 0 , procId); overflow = counter.next( coupledcell.dimension() ); }//while #endif return *this; } //loadMachines /******************************************************************* * Function Name: loadCells ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadCells( CoupledCell &parent, bool printParserInfo ) { string modelName( lowerCase( parent.description() ) ) ; // get the width and height if ( ini.exists( modelName, "dim" ) ) { MASSERTMSG( !ini.exists( modelName, "width" ) && !ini.exists( modelName, "height" ), "The DIM clause can't coexist with the WITDH or the HEIGHT clauses"); Ini::IdList dimension = ini.definition( modelName, "dim" ); CellPosition cp( ini.join(dimension) ); nTupla dims( cp ); MASSERTMSG( dims.dimension() >= 2, "The tuple defined with the DIM clause is invalid. It must have 2 or more elements."); parent.dim( dims ); } else { MASSERTMSG( !ini.exists( modelName, "dim" ), "The DIM clause can't coexist with the WITDH or the HEIGHT clauses"); int width = str2Int( ini.definition( modelName, "width" ).front() ) ; int height = str2Int( ini.definition( modelName, "height" ).front() ) ; parent.dim( DIM_WIDTH, width ); parent.dim( DIM_HEIGHT, height ); } loadStateVariables( parent ) ; Real initialValue( str2Real( ini.definition( modelName, "initialvalue" ).front() ) ) ; parent.initialCellValue( initialValue ) ; bool inertial = ini.definition( modelName, "delay" ).front() == "inertial" ; parent.inertialDelay( inertial ) ; bool wrapped = ini.definition( modelName, "border" ).front() == "wrapped" ; parent.borderWrapped( wrapped ) ; int milSec( str2Int( ini.definition( modelName, "defaultDelayTime" ).front() ) ) ; parent.defaultDelay( VTime( 0, 0, 0, milSec ) ) ; CellPositionList neighborsList ; const Ini::IdList &neighbors( ini.definition( modelName, "neighbors" ) ) ; for( Ini::IdList::const_iterator cursor = neighbors.begin() ; cursor != neighbors.end() ; cursor++ ) neighborsList.push_back( CellPosition( *cursor ) ) ; loadDefaultTransitions( parent, printParserInfo ) ; //Now, before creating the cells, create the local partition CellPartition *partition = new CellPartition (parent.dimension(), parent.borderWrapped()); #ifdef MPI //Iterate along the list of models defined for the current machine for (PIni::IdList::const_iterator cursor = pini.machine(getMachineID()).begin(); cursor != pini.machine(getMachineID()).end(); cursor++) { string modelName, zone; int index = (*cursor).find( '(' ); if( index >= 0 ) { modelName= (*cursor).substr( 0, index ); zone = (*cursor).substr( index ); if ( modelName == parent.description() ) partition->addLocalZone( zone ); } } //for #else //Create a string zone that includes all the cells of the model CellPosition zero( parent.dimension().dimension(),0); CellPosition last = parent.dimension(); for (unsigned i = 0; i < last.dimension(); i++) last.setElement(i, last.get(i)-1); string zone; zone = zero.print() + ".." + last.print(); partition->addLocalZone( zone ); #endif /* Read the NeighborChange ports */ list NCPorts; if ( ini.exists( modelName, "neighborports" ) ) { Ini::IdList::const_iterator cursor; const Ini::IdList &nc_ports( ini.definition( modelName, "neighborports" ) ) ; for(cursor = nc_ports.begin(); cursor != nc_ports.end(); cursor++ ) NCPorts.push_back( *cursor ) ; } //Create the cells. The CellPartition will be owned by the CoupledCell model //so do not delete it. parent.createCells( neighborsList, partition, NCPorts ); loadLocalZones( parent,printParserInfo ) ; //The initial Cell Values will be loaded after the processor has //been initialized. //loadInitialCellValues( parent ) ; return *this ; } /******************************************************************* * Function Name: loadLinks ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadLinks( Coupled &parent ) { string modelName( lowerCase( parent.description() ) ) ; Ini::IdList::const_iterator cursor ; // links ( port(@model)? ) if( ini.exists( modelName, ParallelMainSimulator::linksLabel ) ) { const Ini::IdList &ilist( ini.definition( modelName, ParallelMainSimulator::linksLabel ) ) ; for( cursor = ilist.begin() ; cursor != ilist.end() ; cursor ++ ) { string sourceName, sourcePort, destName, destPort; if( !splitString( *cursor, sourcePort, sourceName, ParallelMainSimulator::separator ) ) sourceName = modelName ; cursor++; // the cursor must be valid if( !splitString( *cursor, destPort, destName, ParallelMainSimulator::separator ) ) destName = modelName ; // addInfluence is a virtual function! // Every class: Coupled, CoupledCell and FlatCoupledCell // will know how to handle it's own case parent.addInfluence( sourceName, sourcePort, destName, destPort ) ; } } return *this ; } /******************************************************************* * Function Name: loadExternalEvents * Description: Jacky: this function is called by the ParallelMainSimulator::run() on * each machine to load external events defined in EV file into the * local NC on each machine * It also sort the loaded external events and points the eventCursor in * the NC to the 1st event in the EventList ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadExternalEvents( istream &fileIn ) { istream_iterator cursor( fileIn ) ; //Jacky: we need to load external events defined in EV file into each NCs, not the Root #ifdef JACKY_REVISION //my version for loading external events into NCs //find out the machine number MachineId mid = ParallelMainSimulator::Instance().getMachineID(); //get the procId of the local NC ProcId NCId = nodeCoordinatorsList[mid]; //get the instance of the local NC from ParallelProcessorAdmin ParallelNodeCoordinator& nc = (ParallelNodeCoordinator&)(SingleParallelProcessorAdmin::Instance().processor(NCId)); #endif //end JACKY_REVISION try { while( cursor != istream_iterator() ) { VTime time( *cursor ) ; cursor ++ ; Port &port( SingleParallelModelAdm::Instance().model("top").port( *cursor ) ) ; cursor ++ ; #ifdef JACKY_REVISION //call addExternalEvent() of the NC nc.addExternalEvent(time, port, str2Real( *cursor )); #else //original version for loading external events into ParallelRoot ParallelRoot::Instance().addExternalEvent( time, port, str2Real( *cursor ) ) ; #endif //end JACKY_REVISION cursor++ ; } } catch( InvalidPortRequest &e ) { e.addLocation( MEXCEPTION_LOCATION() ) ; throw e ; } #ifdef JACKY_REVISION //now, all external events loaded into the local NC //call sort() on the "externalEvents" for the local NC nc.events().sort(); //set the eventCursor pointing to the 1st event in the EventList nc.eventsBegin(); #ifdef JACKY_DEBUG //jacky: the events in the local NC are output to the debug file ostream& jacky_os = JackyDebugStream::Instance().Stream(); jacky_os << "----------------------- external events in NC" << NCId <<": ------------------------" << endl; this->showEvents( nc.events(), jacky_os); jacky_os << "------------------------------------------------------------------------------------" << endl; #endif //end JACKY_DEBUG #else //original version (show external events in the ParallelRoot) this->showEvents( ParallelRoot::Instance().events() ) ; #endif //end JACKY_REVISION return *this; } /******************************************************************* * Function Name: loadInitialCellValues ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadInitialCellValues( CoupledCell &parent ) { if( ini.exists( parent.description(), "initialRow" ) ) { MASSERTMSG( parent.dimension().dimension() == 2, "The initialRow clause must only be used when the dimension is 2"); const Ini::IdList &rowsList( ini.definition( parent.description(), "initialRow" ) ) ; register unsigned row = 0; Ini::IdList::const_iterator cursor = rowsList.begin(); while ( cursor != rowsList.end() ) { // the first value is the row number row = str2Int( (*cursor) ) ; MASSERTMSG( row < parent.dim(DIM_HEIGHT), "The number of row for initialRow is out of range. It's " + int2Str(row) + " and must be in [ 0, " + int2Str( parent.dim(DIM_HEIGHT) - 1 ) + "]" ) ; cursor++ ; // Los siguientes elementos son la descripcion de la fila register unsigned col = 0; while ( col < parent.dim( DIM_WIDTH ) ) { MASSERTMSG( cursor != rowsList.end(), "Insuficient data for initialRow. Last row with " + int2Str(col) + " elements. Note: May be a middle row definition with less elements." ) ; string rowVal( (*cursor) ); nTupla t; t.add(row,col); //If the cell is not within the local partition, //nothing will happen parent.setCellAllValues( CellPosition(t), str2Real(rowVal) ); col++ ; cursor++; } } } if( ini.exists( parent.description(), "initialRowValue" ) ) { MASSERTMSG( parent.dimension().dimension() == 2, "The initialRowValue clause must only be used when the dimension is 2"); const Ini::IdList &rowsList( ini.definition( parent.description(), "initialRowValue" ) ) ; register unsigned row = 0; Real val; for ( Ini::IdList::const_iterator cursor = rowsList.begin(); cursor != rowsList.end(); cursor++ ) { // the first value is the row number row = str2Int( (*cursor) ) ; MASSERTMSG( row < parent.dim(DIM_HEIGHT), "The number of row for initialRowValue is out of range. It's " + int2Str(row) + " and must be in [ 0, " + int2Str( parent.dim(DIM_HEIGHT) - 1 ) + "]" ) ; cursor++ ; MASSERTMSG( cursor != rowsList.end(), "Invalid initial row value for initialRowValue (must be a pair rowNumber rowValues)!" ); // the second is the description of the row string rowVal( *cursor ) ; MASSERTMSG( rowVal.size() == parent.dim(DIM_WIDTH), "The size of the rows for the initial values of the CoupledCell must be equal to the width value !" ); register unsigned col = 0; for (string::iterator rowCurs = rowVal.begin(); rowCurs != rowVal.end(); rowCurs++ ) { if (*rowCurs >= '0' && *rowCurs <= '9') val.value( *rowCurs - '0'); else val = Real::tundef; nTupla t; t.add( row, col); //If the cell is not within the local partition, //nothing will happen parent.setCellAllValues( CellPosition(t), val ); #ifdef JACKY_DEBUG ostream& jacky_os = JackyDebugStream::Instance().Stream(); jacky_os << "### \t CoupledCell::setCellAllValues() called, set value = " << val.value() << " ###" << endl << flush; #endif col++; } } } if( ini.exists( parent.description(), "initialCellsValue" ) ) loadInitialCellValuesFromFile( parent, ini.definition(parent.description(), "initialCellsValue").front() ); if( ini.exists( parent.description(), "initialMapValue" ) ) loadInitialCellValuesFromMapFile( parent, ini.definition(parent.description(), "initialMapValue").front() ); return *this ; } /******************************************************************* * Function Name: loadInitialCellValuesFromFile ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadInitialCellValuesFromFile( CoupledCell &parent, const string &fileName ) { FILE *fileIn; char line[250], *posi; string name(trimSpaces(fileName)); fileIn = fopen( name.c_str(), "r" ); MASSERTMSG( fileIn != NULL, "Can't open the file '" + fileName + "' defined by the initialCellsValue clause"); while (getLineOnFile(fileIn, line)) if (line != NULL && (posi = strchr(line, '=')) != NULL) parent.setCellAllValues( CellPosition(line), str2Real(posi+1) ); fclose(fileIn); return *this; } /******************************************************************* * Function Name: loadInitialCellValuesFromMapFile ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadInitialCellValuesFromMapFile( CoupledCell &parent, const string &fileName ) { FILE *fileIn; char line[250]; string name(trimSpaces(fileName)); fileIn = fopen( name.c_str(), "r" ); MASSERTMSG( fileIn != NULL, "Can't open the file '" + fileName + "' defined by the initialMapValue clause"); CellPosition counter( parent.dimension().dimension(), 0 ); register bool overflow = false; while (!overflow) { MASSERTMSG( getLineOnFile(fileIn, line), "Insuficient data in file specified with InitialMapValue"); parent.setCellAllValues( counter, str2Real(line) ); overflow = counter.next( parent.dimension() ); } fclose(fileIn); return *this; } /******************************************************************* * Function Name: loadStateVariables ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadStateVariables( CoupledCell &parent ) { string modelName( lowerCase( parent.description() ) ) ; // State variables and initial values StateVars statevars; if ( ini.exists( modelName, "statevariables" ) ) { const Ini::IdList &statevariables( ini.definition( modelName, "statevariables" ) ) ; if ( ini.exists( modelName, "statevalues" ) ) { const Ini::IdList &initialvalues( ini.definition( modelName, "statevalues" ) ) ; Ini::IdList::const_iterator cursor_sv = statevariables.begin(); Ini::IdList::const_iterator cursor_iv = initialvalues.begin(); while (cursor_sv != statevariables.end() && cursor_iv != initialvalues.end()) { Real value = str2Real( *cursor_iv ); MASSERTMSG( statevars.createVariable( *cursor_sv, value ), modelName + "/" + "statevariables - Duplicated name: " + *cursor_sv ) ; cursor_sv++; cursor_iv++; } MASSERTMSG( cursor_iv == initialvalues.end() && cursor_sv == statevariables.end(), modelName + "/" + "statevalues - there must be as many state values as state variables" ) ; } else { // No initial values for ( Ini::IdList::const_iterator cursor_sv = statevariables.begin(); cursor_sv != statevariables.end(); cursor_sv++ ) MASSERTMSG( statevars.createVariable( *cursor_sv ), modelName + "/" + "statevariables - Duplicated name: " + *cursor_sv ) ; } } else MASSERTMSG( !ini.exists( modelName, "statevalues" ), modelName + "/" + "statevalues - statevariables needed" ) parent.initialStateVars( statevars ); return *this ; } /******************************************************************* * Function Name: loadInitialVariablesValues ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadInitialVariablesValues( CoupledCell &parent ) { if( ini.exists( parent.description(), "initialVariablesValue" ) ) loadInitialVariablesValuesFromFile( parent, ini.definition(parent.description(), "initialVariablesValue").front() ); return *this ; } /******************************************************************* * Function Name: loadInitialVariablesValuesFromFile ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadInitialVariablesValuesFromFile( CoupledCell &parent, const string &fileName ) { FILE *fileIn; char line[250], *posi; string name(trimSpaces(fileName)); fileIn = fopen( name.c_str(), "r" ); MASSERTMSG( fileIn != NULL, "Can't open the file '" + fileName + "' defined by the initialVariablesValue clause"); while (getLineOnFile(fileIn, line)) if (line != NULL && (posi = strchr(line, '=')) != NULL) parent.setVariablesValue( CellPosition(line), (const char *) (posi+1) ); fclose(fileIn); return *this; } /******************************************************************* * Function Name: loadDefaultTransitions ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadDefaultTransitions( CoupledCell &parent, bool printParserInfo ) { if( ini.exists( parent.description(), "localTransition" ) ) { parent.localTransition( ini.definition( parent.description(), "localTransition" ).front() ) ; registerTransition( parent.localTransition(), printParserInfo ); } return *this; } /******************************************************************* * Function Name: loadPortInTransitions ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadPortInTransitions( CoupledCell &parent, bool printParserInfo ) { // Only for CoupledCell and FlatCoupledCell if( ini.exists( parent.description(), "portintransition" ) ) { const Ini::IdList &portInTranList( ini.definition( parent.description(), "portintransition" ) ) ; // define Cursor for( Ini::IdList::const_iterator cursor = portInTranList.begin() ; cursor != portInTranList.end() ; cursor++ ) { string modelAndPortName( *cursor ) ; cursor++; MASSERTMSG( cursor != portInTranList.end(), "Invalid portInTransition specification. Second parameter missing!" ) ; string actionName( *cursor ), sourcePort, sourceName; MASSERTMSG( splitString( modelAndPortName, sourcePort, sourceName, ParallelMainSimulator::separator ), "Invalid portName@cellModelName in portInTransition" ); //////////////////////////////////////////////////// // get the ELSE statement string elseFunction( "" ); if( ini.exists( actionName, "else" ) ){ elseFunction = ini.definition( actionName, "else" ).front() ; MASSERTMSG( elseFunction != actionName, "The Else Function '" + elseFunction + "' can't be the same as the portInFunction.\nProbably it will generate an infinite loop." ); string ef = elseFunction, elseEF; while (ef != "") { elseEF = ""; if( ef != "" && ini.exists( ef, "else" ) ) elseEF = ini.definition( ef, "else" ).front() ; MASSERTMSG( ef != elseEF, "The Else Function '" + ef + "' can't be the same as the portInFunction.\nProbably it will generate an infinite loop." ); registerTransitionPortIn( ef, printParserInfo, elseEF ); ef = elseEF; } } ////////////////////////////////////////////////////// // parse the function definition registerTransitionPortIn( actionName, printParserInfo, elseFunction ); // NOTE: If the port not exist, the setPortInFunction will produce an exception. // Now, make an association between the function and the input port parent.setPortInFunction( sourceName, sourcePort, actionName ); } } return *this ; } /******************************************************************* * Function Name: loadLocalZones ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::loadLocalZones( CoupledCell &parent, bool printParserInfo ) { if( ini.exists( parent.description(), "zone" ) ) { const Ini::IdList &zoneList( ini.definition( parent.description(), "zone" ) ) ; // zone Cursor for( Ini::IdList::const_iterator zoneCurs = zoneList.begin() ; zoneCurs != zoneList.end() ; zoneCurs++ ) { string fname( *zoneCurs ) ; registerTransition( fname, printParserInfo ); zoneCurs++ ; MASSERTMSG( zoneCurs != zoneList.end() && *zoneCurs == "{", "Invalid zone specification, '{' missing!" ) ; zoneCurs++ ; while( zoneCurs != zoneList.end() && *zoneCurs != "}" ) { Zone zone( *zoneCurs ); for( Zone::Iterator cursor = zone.begin(); cursor != zone.end(); cursor++ ) parent.setLocalTransition( *cursor, fname ); zoneCurs++; } MASSERTMSG( zoneCurs != zoneList.end() && *zoneCurs == "}", "Invalid zone specification, '}' missing!" ) ; } // zone Cursor } return *this ; } /******************************************************************* * Method: registerTransition ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::registerTransition(const LocalTransAdmin::Function &fName, bool printParserInfo ) { if( !SingleLocalTransAdmin::Instance().isRegistered( fName ) ) { if( ini.exists( fName ) && ini.exists( fName, "rule" ) ) { const Ini::IdList &fnList( ini.definition( fName, "rule" ) ) ; strstream buffer ; for( Ini::IdList::const_iterator cursor = fnList.begin() ; cursor != fnList.end() ; cursor++ ) buffer << " " << *cursor ; if( printParserInfo == true ) { ParserDebug().Stream() << "********* BUFFER ********" << endl ; ParserDebug().Stream().write(buffer.str(), buffer.pcount() ); ParserDebug().Stream() << endl ; } SingleLocalTransAdmin::Instance().registerTransition( fName, buffer, printParserInfo, false) ; } else { MException e( string( "The local transition " ) + fName + " is missing in the ini file!" ) ; MTHROW( e ) ; } } return *this; } /******************************************************************* * Method: registerTransitionPortIn ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::registerTransitionPortIn(const LocalTransAdmin::Function &fName, bool printParserInfo, const string &elseFunction ) { if( !SingleLocalTransAdmin::Instance().isRegistered( fName ) ) { if( ini.exists( fName ) && ini.exists( fName, "rule" ) ) { const Ini::IdList &fnList( ini.definition( fName, "rule" ) ) ; strstream buffer ; for( Ini::IdList::const_iterator cursor = fnList.begin() ; cursor != fnList.end() ; cursor++ ) buffer << " " << *cursor ; if( printParserInfo == true ) { ParserDebug().Stream() << "********* BUFFER (for PortIn Transition) ********" << endl ; ParserDebug().Stream().write( buffer.str(), buffer.pcount() ) ; ParserDebug().Stream() << endl ; } SingleLocalTransAdmin::Instance().registerTransition( fName, buffer, printParserInfo, true, elseFunction) ; } else { MException e( string( "The local transition " ) + fName + " is missing in the ini file!" ) ; MTHROW( e ) ; } } return *this; } /******************************************************************* * Function Name: showEvents ********************************************************************/ void ParallelMainSimulator::showEvents( const EventList &events, ostream &out ){ MachineId mid = ParallelMainSimulator::Instance().getMachineID(); ProcId NCId = nodeCoordinatorsList[mid]; ParallelNodeCoordinator& nc = (ParallelNodeCoordinator&)(SingleParallelProcessorAdmin::Instance().processor(NCId)); for (EventList::const_iterator cursor = events.begin() ; cursor != events.end() ; cursor++ ) { if( cursor == nc.currentEvent() ){ out << "<*>" << flush; } out << cursor->asString() << endl << flush; } if( nc.endOfEvents() ){ out << "==== currentEvent() -> END ====" << endl << flush; } } /******************************************************************* * Function Name: showLogInfo * Lists all the log files associated to each model. The output will * be used by drawlog. * * Jacky Note: * NCs and FCs on other machines (i.e. on machine1, machine2, etc) are NOT * included in the modelDB. Only the NC and FC on the current machine (machine0) * are in the modelDB. In order to include the log file names for those remote * NCs and FCs, we need to deal with them separately. ********************************************************************/ //Jacky Note [2006-04-26] //"One Log File per Node" strategy is implemented here to improve the performance! //The content of the "index log file" should have: // group name -> [logfiles] // def name -> LogFileNames // def list -> the "LogFileNames" list includes all the log file names // a distinct log file name for each node //The log files are created for the NCs if -LY is not used; otherwise, they are created for the FCs void ParallelMainSimulator::showLogInfo( ostream &out = cout ) { #ifndef JACKY_UNIQUE_LOG //[2006-04-26] const ParallelModelAdmin::ModelDB& models( SingleParallelModelAdm::Instance().models()); #endif //end JACKY_UNIQUE_LOG [2006-04-26] out << "[logfiles]" << endl; #ifndef JACKY_LOG_FILE //---- This is the original version, which does not include remote NCs and FCs ---- for (ParallelModelAdmin::ModelDB::const_iterator cursor = models.begin() ; cursor != models.end(); cursor++) { Model* model = cursor->second; out << model->description() << " : "; for(ModelPartition::const_iterator mcursor = model->modelPartition().begin(); mcursor != model->modelPartition().end(); mcursor++) { string logfilename(logName() + mcursor->second); out << logfilename << " "; } out << endl; } #else //----------------------- New version to include remote NCs and FCs ----------------------------------- #ifndef JACKY_UNIQUE_LOG //[2006-04-26] ============ previous PCD++ version ============ #ifdef JACKY_SINGLE_LOG_FILE_LY //[2006-04-20] if( Log::Default.createLog() && (Log::Default.logType() != 8) ){ //In this case, we still create all log files for all processors #endif //end JACKY_SINGLE_LOG_FILE_LY [2006-04-20] //1. print out all models in the modelDB except the NCs and FCs for (ParallelModelAdmin::ModelDB::const_iterator cursor = models.begin() ; cursor != models.end(); cursor++) { Model* model = cursor->second; string model_desp = model->description(); if((model_desp != "ParallelNodeCoordinator") && (model_desp != "ParallelFlatCoordinator")){ out << model_desp << " : "; for(ModelPartition::const_iterator mcursor = model->modelPartition().begin(); mcursor != model->modelPartition().end(); mcursor++) { string logfilename(logName() + mcursor->second); out << logfilename << " "; } out << endl; } } //2. now print the log file names for the NCs out << "ParallelNodeCoordinator : "; for(ParallelMainSimulator::NodeCoordinatorsList::const_iterator nc_cursor = nodeCoordinatorsList.begin(); nc_cursor != nodeCoordinatorsList.end(); nc_cursor++){ string nclogfilename(logName() + nc_cursor->second); out << nclogfilename << " "; } out << endl; //3. now print the log file names for the FCs out << "ParallelFlatCoordinator : "; for(ParallelMainSimulator::FlatCoordinatorsList::const_iterator fc_cursor = flatCoordinatorsList.begin(); fc_cursor != flatCoordinatorsList.end(); fc_cursor++){ string fclogfilename(logName() + fc_cursor->second); out << fclogfilename << " "; } out << endl; #ifdef JACKY_SINGLE_LOG_FILE_LY //[2006-04-20] } else if( Log::Default.createLog() ){ //In this case, we only create log files for FCs //Only show log file names for the FCs out << "ParallelFlatCoordinator : "; for(ParallelMainSimulator::FlatCoordinatorsList::const_iterator fc_cursor = flatCoordinatorsList.begin(); fc_cursor != flatCoordinatorsList.end(); fc_cursor++){ string fclogfilename(logName() + fc_cursor->second); out << fclogfilename << " "; } out << endl; } #endif //end JACKY_SINGLE_LOG_FILE_LY [2006-04-20] #else //JACKY_UNIQUE_LOG [2006-04-26] ============ new PCD++ version ============ //we only need to print out the log file names for the NCs if -LY is not used; //or the log file names fo the FCs if -LY is given. if ( Log::Default.createLog() && (Log::Default.logType() != 8) ) { //if create log & -LY is not given //-LY is not given, we create log files for the NCs //use "logfilename.log + NC_id" as the log file names out << "LogFileNames : "; for(ParallelMainSimulator::NodeCoordinatorsList::const_iterator nc_cursor = nodeCoordinatorsList.begin(); nc_cursor != nodeCoordinatorsList.end(); nc_cursor++) { string nclogfilename(logName() + nc_cursor->second); out << nclogfilename << " "; } out << endl; } else if ( Log::Default.createLog() ){ //-LY is given, we create log files for the FCs //use "logfilename.log + FC_id" as the log file names out << "LogFileNames : "; for(ParallelMainSimulator::FlatCoordinatorsList::const_iterator fc_cursor = flatCoordinatorsList.begin(); fc_cursor != flatCoordinatorsList.end(); fc_cursor++) { string fclogfilename(logName() + fc_cursor->second); out << fclogfilename << " "; } out << endl; } #endif //end JACKY_UNIQUE_LOG [2006-04-26] ====================================== #endif //end JACKY_LOG_FILE --------------------------------------------------------------------------------------- } /******************************************************************* * Function Name: setUpLogicalProcess ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::setUpLogicalProcess() { //ostream& out = debugStream(); const ParallelModelAdmin::ModelDB& models(SingleParallelModelAdm::Instance().models()); //Create a new Logical Process. //Remember that in addition to all the model objects, there exists //the Root Processor, a Warped object! //cerr << "[" << ParallelMainSimulator::Instance().getMachineID() << "] Setting up the logical process " << endl; int totalMachinesCount = SingleParallelModelAdm::Instance().totalMachinesCount(); //int totalObjectsCount = SingleParallelModelAdm::Instance().totalObjectsCount(); int totalObjectsCount = SingleParallelModelAdm::Instance().totalObjectsCount() + (totalMachinesCount * 2); // + (machines * 2) (one NC and one FC for each machine) //int localObjectsCount = SingleParallelModelAdm::Instance().localObjectsCount(); int localObjectsCount = SingleParallelModelAdm::Instance().localObjectsCount() + 1 + 1; // +1 (NC) +1 (FC) int myMachineId = ParallelMainSimulator::Instance().getMachineID(); #ifdef JACKY_DEBUG ostream& jacky_os = JackyDebugStream::Instance().Stream(); jacky_os << "-----------------------------------------------------------------------------------" << endl; jacky_os << "[" << myMachineId << "] Total objects : " << totalObjectsCount << endl; jacky_os << "[" << myMachineId << "] Local objects : " << localObjectsCount << endl; jacky_os << "[" << myMachineId << "] Total machines : " << totalMachinesCount << endl; jacky_os << "-----------------------------------------------------------------------------------" << endl; //$$$jacky end #else if(myMachineId != 0){ cerr << "[" << myMachineId << "] Local objects : " << localObjectsCount << endl; } else { cerr << "[" << myMachineId << "] Local objects : " << localObjectsCount << endl; cerr << "Total objects : " << totalObjectsCount << " / Total machines : " << totalMachinesCount << endl; } #endif lp = new LogicalProcess(totalObjectsCount, localObjectsCount, totalMachinesCount); //cerr << "[" << ParallelMainSimulator::Instance().getMachineID() // << "] LP has been created. Now registering processors." << endl; //Now, register all DEVS processors that are going to run in this LP. for (ParallelModelAdmin::ModelDB::const_iterator cursor = models.begin() ; cursor != models.end(); cursor++) { Model* model = cursor->second; //If the model has a local processor on this LP if(model->localProc() != ParallelProcessor::InvalidId) { ParallelProcessor &proc = model->createParallelProcessor(); lp->registerObject(&proc); // cout << "\tRegistering processor " << proc.description() << "(" << proc.id() << ")" << endl; } } return *this; } /******************************************************************* * Function Name: afterInitialize ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::afterInitialize() { const ParallelModelAdmin::ModelDB& models(SingleParallelModelAdm::Instance().models()); for (ParallelModelAdmin::ModelDB::const_iterator cursor = models.begin() ; cursor != models.end(); cursor++) { Model* model = cursor->second; //If the model has a local processor on this LP if(model->localProc() != ParallelProcessor::InvalidId) { model->afterProcessorInitialize(); } } return *this; } /******************************************************************* * Function Name: showModelPatition ********************************************************************/ void ParallelMainSimulator::showModelPartition(ostream &out = cout ) { const ParallelModelAdmin::ModelDB& models( SingleParallelModelAdm::Instance().models()); for (ParallelModelAdmin::ModelDB::const_iterator cursor = models.begin() ; cursor != models.end(); cursor++) { Model* model = cursor->second; out << "Model: " << model->description() << endl; out << "\tMachines: " << endl;; for(ModelPartition::const_iterator mcursor = model->modelPartition().begin(); mcursor != model->modelPartition().end(); mcursor++) { out << "\t\t Machine: " << mcursor->first << "\tProcId: " << mcursor->second; if ( mcursor->second == model->localProc() ) out << " < local > "; if ( mcursor->second == model->masterId()) out << " < master > "; out << endl; } out << endl; } } /******************************************************************* * Method: splitString ********************************************************************/ bool ParallelMainSimulator::splitString( const string &full, string &first, string &second, char separator ) { first = second = ""; register int index = full.find( separator ); if( index >= 0 ) { first = full.substr( 0, index ); second = full.substr( index + 1 ); } else first = full; return index >= 0; } int getLineOnFile(FILE *fileIn, char *linea) { #define FILE_BUFFER_SIZE 25000 static char buffer[FILE_BUFFER_SIZE]; static long leido = FILE_BUFFER_SIZE; static long porLeer = FILE_BUFFER_SIZE; register bool encontre = false; register long pos = 0; while (!encontre) { if (leido == FILE_BUFFER_SIZE || porLeer == 0) { if (feof(fileIn) || (porLeer = fread( buffer, 1, FILE_BUFFER_SIZE, fileIn )) == 0) return 0; leido = 0; } if (buffer[leido] != '\n') linea[pos++] = buffer[leido++]; else { encontre = true; leido++; } porLeer--; } linea[pos] = 0; return 1; } /******************************************************************* * Function Name: debugStream ********************************************************************/ ostream& ParallelMainSimulator::debugStream() { if ( (!vDebugStream) ) { if ( loader()->partitionDebugName() != "/dev/null" ) { string filename = loader()->partitionDebugName() + getMachineID(); vDebugStream = new fstream( filename.c_str(), ios::out); } else { vDebugStream = new fstream( "/dev/null", ios::out); } } return *vDebugStream; } /******************************************************************* * Function Name: debugFlattenedLinks * Description: Shows the flattened links for the model ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::debugFlattenedLinks() { //cerr << "[" << getMachineID() << "] debugFlattenedLinks() at ParallelMainSimulator" << endl << flush; //cerr << "[" << getMachineID() << "] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" << endl << flush; #ifdef JACKY_DEBUG ostream& jacky_os = JackyDebugStream::Instance().Stream(); //output the status of all the links jacky_os << endl << "---------------- debugFlattenedLinks() -----------------------------" << endl; for (PortLinksList::const_iterator cursor = allPortLinks().begin() ; cursor != allPortLinks().end() ; cursor++){ //Jacky: sourcePortId ==> destinationPort* PortId idOriginPort = cursor->first; Port *destPort = cursor->second; //cerr << "[" << getMachineID() << "] OID: " << idOriginPort << " -> DID: " << destPort->id() << " == " ; //cerr << "[" << getMachineID() << "]" << allPorts()[idOriginPort]->model().description() << " " // << allPorts()[idOriginPort]->asString() << " ->" ; //cerr << "[" << getMachineID() << "]" << allPorts()[destPort->id()]->model().description() // << " " << allPorts()[destPort->id()]->asString() << endl << flush; int i = 1; jacky_os << "\tLink" << i << " : " << allPorts()[idOriginPort]->name() << "@" << allPorts()[idOriginPort]->model().description() << "[" << idOriginPort << "]" << " --> " << allPorts()[destPort->id()]->name() << "@" << allPorts()[destPort->id()]->model().description() << "[" << destPort->id() << "]" <id() ) PortId idOriginPort = cursor->first; Port *destPort = cursor->second; // Retrieve all links like (destPort->id(), w) and add a link (idOriginPort, w) if it doesn't exist yet // Get elements from destPort->id() = idDestination pair g = allPortLinks().equal_range( destPort->id() ); for (MI innercursor = g.first ; innercursor != g.second ; ++innercursor) { //PortId oldDestPortId = innercursor->first; // Commented out to avoid warning, unused variable Port *newDestPort = innercursor->second; //cerr << allPorts()[idOriginPort]->model().description() << " " << allPorts()[idOriginPort]->asString() << " ->" ; //cerr << " " << allPorts()[newDestPort->id()]->model().description() << " " << allPorts()[newDestPort->id()]->asString() << endl; // Check if the link already exists // So we need to get all the links with origin port = idOriginPort bool exists = false; pair e = allPortLinks().equal_range( idOriginPort ); for (MI existingcursor = e.first ; existingcursor != e.second ; ++existingcursor) { // is this the port we are looking for? ( idOriginPort, newDestPort->id() ) // If so, we won't add it to the linksList if ( (existingcursor->second)->id() == newDestPort->id() ) { //cerr << "Already exists, port: " << idOriginPort << " to " << newDestPort->id() << endl ; exists = true; } // if } // for existingcursor // if it doesn't exist, then add it if (!exists) { allPortLinks().insert( make_pair(idOriginPort, newDestPort) ); modified = true; // we will loop again because there are new links that have been added } // if } //for innercursor } // for cursor } //while return *this; } // flattenLinks() /******************************************************************* * Function Name: debugInputPorts * Description: Shows the input ports ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::debugInputPorts() { /* typedef PortLinksList::const_iterator MI; for (MI cursor = allInputPorts().begin() ; cursor != allInputPorts().end() ; cursor++) { PortId pi = cursor->first ; Port &portX = *(cursor->second) ; cout << "[" << getMachineID() << "] PortId: " << pi << " name: " << portX.asString() << " belongs to: " << portX.model().description() << endl << flush; } */ return *this; } /******************************************************************* * Function Name: debugOutputPorts * Description: Shows the output ports ********************************************************************/ ParallelMainSimulator &ParallelMainSimulator::debugOutputPorts() { /* typedef PortLinksList::const_iterator MI; for (MI cursor = allOutputPorts().begin() ; cursor != allOutputPorts().end() ; cursor++) { PortId pi = cursor->first ; Port &portX = *(cursor->second) ; cout << "[" << getMachineID() << "] PortId: " << pi << " name: " << portX.asString() << " belongs to: " << portX.model().description() << endl << flush; } */ return *this; } #ifdef JACKY_DEBUG //$$$jacky $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ //$ Function Name: printSimArray() : 2005-08-02 //print the simArray in each LP into a file //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ void ParallelMainSimulator::printSimArray(ostream& out){ out << "Machine" << ParallelMainSimulator::Instance().getMachineID() << ":" << endl; //get the simArray from the lp ObjectRecord* mysimArray = ParallelMainSimulator::Instance().getLP()->simArray; //Note: each ObjectRecord has a lpId and a ptr to the ParallelProcessor int totalMachinesCount = SingleParallelModelAdm::Instance().totalMachinesCount(); int arraySize = SingleParallelModelAdm::Instance().totalObjectsCount() + (totalMachinesCount * 2); out << "--------------------------- simArray on this LP -----------------------------------" << endl; for(int i = 0; i < arraySize; i++){ int lpid = mysimArray[i].lpNum; BasicTimeWarp* proc = mysimArray[i].ptr; out << "simArray[" << i << "] : LP[" << lpid << "] <=> procId[" << proc->id <<"] / TYPE = " << typeid(*proc).name() << " / localId[" << proc->localId << "]" << endl; } out << "-----------------------------------------------------------------------------------" << endl; } //$$$jacky $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ //$ Function Name: printModels() : 2005-08-02 //print all models in ModelDB on each machine //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ void ParallelMainSimulator::printModels(ostream& out){ const ParallelModelAdmin::ModelDB& models(SingleParallelModelAdm::Instance().models()); out << "-------------------All Models in ModelDB : ------------------------------------" << endl; for (ParallelModelAdmin::ModelDB::const_iterator cursor = models.begin() ; cursor != models.end(); cursor++) { ModelId mid = cursor->first; Model* model = cursor->second; out << "modelID = " << mid << " -> Model: id=" << model->id() << " description=" << model->description() << " localProc=" << model->localProc() << " masterId=" << model->masterId() << " parentId=" << model->parentId() << " atomic?" << model->isAtomic() << endl; } out << "-------------------------------------------------------------------------------" << endl; } //$$$jacky $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ //$ Function Name: printProcessors() : 2005-08-22 //print all processors in ProcessorDB on each machine //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ void ParallelMainSimulator::printProcessors(ostream& out){ ParallelProcessorAdmin::ProcessorDB& processors = SingleParallelProcessorAdmin::Instance().getProcessorDB(); out << "-------------------All Processors in ProcessorDB : ------------------------------------" << endl; for (ParallelProcessorAdmin::ProcessorDB::const_iterator cursor = processors.begin() ; cursor != processors.end(); cursor++) { ProcId pid = cursor->first; ParallelProcessor* proc = cursor->second; out << "procID = " << pid << " <" << (unsigned long)proc << "> ->" << (proc->model()).asString() << " / STATE_MANAGER address = " << proc->state << endl; } out << "-------------------------------------------------------------------------------" << endl; } //$$$jacky $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ //$ Function Name: printNCList() : 2005-08-19 //print the NodeCoordinatorsList in this ParallelMainSimulator //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ void ParallelMainSimulator::printNCList(ostream& out){ out << "----------------------- NodeCoordinatorsList --------------------------------------" << endl; for(ParallelMainSimulator::NodeCoordinatorsList::const_iterator cursor = nodeCoordinatorsList.begin(); cursor != nodeCoordinatorsList.end(); cursor++){ MachineId machineid = cursor->first; ProcId procid = cursor->second; out << "MachineID = " << machineid << " -> " << procid << endl; } out << "-----------------------------------------------------------------------------------" << endl; } //$$$jacky $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ //$ Function Name: printNCList() : 2005-08-19 //print the FlatCoordinatorsList in this ParallelMainSimulator //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ void ParallelMainSimulator::printFCList(ostream& out){ out << "----------------------- FlatCoordinatorsList --------------------------------------" << endl; for(ParallelMainSimulator::FlatCoordinatorsList::const_iterator cursor = flatCoordinatorsList.begin(); cursor != flatCoordinatorsList.end(); cursor++){ MachineId machineid = cursor->first; ProcId procid = cursor->second; out << "MachineID = " << machineid << " -> " << procid << endl; } out << "-----------------------------------------------------------------------------------" << endl; } //$$$jacky $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ //$ Function Name: printDependantList() : 2005-08-19 //print DependantLists in each ParallelCoordinator (Master and Slave) //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ void ParallelMainSimulator::printDependantList(ostream& out){ const ParallelProcessorAdmin::ProcessorDB& procs( SingleParallelProcessorAdmin::Instance().getProcessorDB()); //map out << "----------------------- DependantList --------------------------------------" << endl; for (ParallelProcessorAdmin::ProcessorDB::const_iterator cursor = procs.begin() ; cursor != procs.end(); cursor++) { ParallelProcessor* proc = cursor->second; ParallelCoordinator* coor = dynamic_cast(proc); if(coor){ //cast is succeed, a ParallelCoordinator is found out << "coordinator [procid=" << coor->id() << " for " << (coor->model()).description() << "] dependants: " << endl; ParallelCoordinatorState::DependantList dependants = coor->dependants(); for(ParallelCoordinatorState::DependantList::const_iterator cursor2 = dependants.begin(); cursor2 != dependants.end(); cursor2++){ out << "\tprocid = " << cursor2->first << " VTime = " << cursor2->second << endl; } } } out << "-----------------------------------------------------------------------------------" << endl; } //$$$jacky $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ //$ Function Name: printSlaves() : 2005-08-19 //print slave coordinators for each ParallelMCoordinator //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ void ParallelMainSimulator::printSlaves(ostream& out){ const ParallelProcessorAdmin::ProcessorDB& procs( SingleParallelProcessorAdmin::Instance().getProcessorDB()); //map out << "----------------------- Slaves --------------------------------------" << endl; for (ParallelProcessorAdmin::ProcessorDB::const_iterator cursor = procs.begin() ; cursor != procs.end(); cursor++) { ParallelProcessor* proc = cursor->second; ParallelMCoordinator* coor = dynamic_cast(proc); if(coor){ //cast is succeed, a ParallelMCoordinator is found out << "Master Coordinator [procid=" << coor->id() << " for " << (coor->model()).description() << "] slaves: " << endl; ParallelCoordinatorState::DependantList slaves = coor->slaves(); for(ParallelCoordinatorState::DependantList::const_iterator cursor2 = slaves.begin(); cursor2 != slaves.end(); cursor2++){ out << "\tprocid = " << cursor2->first << " VTime = " << cursor2->second << endl; } } } out << "-----------------------------------------------------------------------------------" << endl; } //$$$jacky $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ //$ Function Name: getEventsInNC() : 2005-08-22 //get the EventList "externalEvents" in the ParallelNodeCoordinator //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ const EventList& ParallelMainSimulator::getEventsInNC(){ //1> get the NC procId on this machine ProcId ncId = this->nodeCoordinatorsList[this->getMachineID()]; //2> get the NC from ParallelProcessorAdmin ParallelNodeCoordinator& nc = dynamic_cast(SingleParallelProcessorAdmin::Instance().processor(ncId)); //3> return the "externalEvents" return nc.events(); } /* //$$$jacky $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ //$ Function Name: getEventsInFC() : 2005-08-22 //get the EventList "externalEvents" in the ParallelFlatCoordinator //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ const EventList& ParallelMainSimulator::getEventsInFC(){ //1> get the FC procId on this machine ProcId fcId = this->flatCoordinatorsList[this->getMachineID()]; //2> get the FC from ParallelProcessorAdmin ParallelFlatCoordinator& fc = dynamic_cast(SingleParallelProcessorAdmin::Instance().processor(fcId)); //3> return the "externalEvents" return fc.events(); } */ #endif //end JACKY_DEBUG