void Element::setTick( int t ) { Id clockId( 1 ); if ( t == tick_ ) return; if ( tick_ >= 0 ) { // Drop all messages coming here from clock. dropAllMsgsFromSrc( clockId ); } tick_ = t; if ( t < 0 || t > 31 ) { // Only 32 ticks available. // Don't need to add new ticks. return; } const Finfo* f2 = cinfo()->findFinfo( "init" ); if ( f2 && dynamic_cast< const SharedFinfo* >( f2 ) ) { // Must build init msg too. This comes on the previous tick. assert( t > 0 ); addClockMsg( t-1, id(), f2 ); } f2 = cinfo()->findFinfo( "proc" ); if ( f2 ) { addClockMsg( t, id(), f2 ); } else { cout << "Element::setTick:Warning: Attempt to assign a tick to a '" << cinfo_->name() << "'.\nThis does not support process actions.\n"; tick_ = -1; } }
/** * Static function, used to flip flags to start or end a simulation. * It is used as the within-barrier function of barrier 3. * This has to be in the barrier as we are altering a Clock field which * the 'process' flag depends on. * Six cases: * - Do nothing * - Reinit only * - Reinit followed by start * - Start only * - Stop only * - Stop followed by Reinit. * Some of these cases need additional intermediate steps, since the reinit * flag has to turn itself off after one cycle. */ void Clock::checkProcState() { /// Handle pending Reduce operations. Qinfo::clearReduceQ( Shell::numProcessThreads() ); if ( procState_ == NoChange ) { // Most common return; } Id clockId( 1 ); assert( clockId() ); Clock* clock = reinterpret_cast< Clock* >( clockId.eref().data() ); switch ( procState_ ) { case TurnOnReinit: clock->doingReinit_ = 1; // procState_ = TurnOffReinit; break; case TurnOffReinit: clock->doingReinit_ = 0; procState_ = NoChange; break; case ReinitThenStart: clock->doingReinit_ = 1; procState_ = StartOnly; break; case StartOnly: clock->doingReinit_ = 0; clock->isRunning_ = 1; procState_ = NoChange; break; case StopOnly: clock->isRunning_ = 0; procState_ = NoChange; break; case StopThenReinit: clock->isRunning_ = 0; clock->doingReinit_ = 1; // procState_ = TurnOffReinit; break; case NoChange: default: break; } }
double Neutral::getDt( const Eref& e ) const { int tick = e.element()->getTick(); if ( tick < 0 ) return 0.0; Id clockId( 1 ); return LookupField< unsigned int, double >::get( clockId, "tickDt", tick ); }
void Shell::doReinit( ) { #ifdef ENABLE_LOGGER clock_t t = clock(); cout << logger.dumpStats(0); #endif Id clockId( 1 ); SetGet0::set( clockId, "reinit" ); #ifdef ENABLE_LOGGER float time = (float(clock() - t)/CLOCKS_PER_SEC); logger.initializationTime.push_back(time); #endif }
void Shell::doStart( double runtime ) { #ifdef ENABLE_LOGGER clock_t t = clock(); stringstream ss; ss << "Running moose for " << runtime << " seconds"; logger.log("INFO", ss.str()); #endif Id clockId( 1 ); SetGet1< double >::set( clockId, "start", runtime ); #ifdef ENABLE_LOGGER float time = (float(clock() - t) / CLOCKS_PER_SEC); logger.simulationTime.push_back(time); #endif }
/** * In phase2 it advances the internal counter to move to the next tick, * and when all ticks for this TickManager are done, to move to the next * TickManager. */ void Clock::reinitPhase2( ProcInfo* info ) { info->currTime = 0.0; if ( Shell::isSingleThreaded() || info->threadIndexInGroup == 1 ) { if ( tickPtr_.size() == 0 || tickPtr_[ currTickPtr_ ].mgr()->reinitPhase2( info ) ) { ++currTickPtr_; if ( currTickPtr_ >= tickPtr_.size() ) { Id clockId( 1 ); ack()->send( clockId.eref(), info->threadIndexInGroup, info->nodeIndexInGroup, OkStatus ); procState_ = TurnOffReinit; ++countReinit2_; } } } }
// In phase 2 we need to do the updates to the Clock object, especially // sorting the TickPtrs. This also is when we find out if the simulation // is finished. // Note that this function happens when lots of other threads are doing // things. So it cannot touch any fields which might affect other threads. void Clock::advancePhase2( ProcInfo *p ) { if ( Shell::isSingleThreaded() || p->threadIndexInGroup == 1 ) { tickPtr_[0].mgr()->advancePhase2( p ); if ( tickPtr_.size() > 1 ) sort( tickPtr_.begin(), tickPtr_.end() ); currentTime_ = tickPtr_[0].mgr()->getNextTime() - tickPtr_[0].mgr()->getDt(); if ( currentTime_ > endTime_ ) { Id clockId( 1 ); procState_ = StopOnly; finished()->send( clockId.eref(), p->threadIndexInGroup ); ack()->send( clockId.eref(), p->threadIndexInGroup, p->nodeIndexInGroup, OkStatus ); } ++countAdvance2_; } }
static bool addClockMsg( unsigned int tick, Id tgt, const Finfo* f2 ) { Id clockId( 1 ); stringstream ss; ss << "proc" << tick; const Finfo* f1 = clockId.element()->cinfo()->findFinfo( ss.str() ); assert( f1 ); assert( f2 ); Msg* m = new OneToAllMsg( clockId.eref(), tgt.element(), 0 ); if ( m ) { if ( f1->addMsg( f2, m->mid(), clockId.element() ) ) { return true; } delete m; } cout << "Error: Element::setTick: failed to connect " << tgt << " to clock\n"; return false; }
// Non-static function. The innerAddMsg needs the shell. void Shell::addClockMsgs( const vector< ObjId >& list, const string& field, unsigned int tick, unsigned int msgIndex ) { if ( !Id( 1 ).element() ) return; ObjId clockId( 1 ); dropClockMsgs( list, field ); // Forbid duplicate PROCESS actions. for ( vector< ObjId >::const_iterator i = list.begin(); i != list.end(); ++i ) { if ( i->element() ) { stringstream ss; ss << "proc" << tick; const Msg* m = innerAddMsg( "OneToAll", clockId, ss.str(), *i, field, msgIndex++ ); if ( m ) i->element()->innerSetTick( tick ); } } }
void Shell::doStop( ) { Id clockId( 1 ); SetGet0::set( clockId, "stop" ); }