uint32_t Config::finishAllFrames() { if( _finishedFrame == _currentFrame ) return _currentFrame; EQLOG( co::base::LOG_ANY ) << "-- Finish All Frames --" << std::endl; ConfigFinishAllFramesPacket packet; send( getServer(), packet ); ClientPtr client = getClient(); const uint32_t timeout = getTimeout(); while( _finishedFrame < _currentFrame ) { try { client->processCommand( timeout ); } catch( const co::Exception& e ) { EQWARN << e.what() << std::endl; break; } } handleEvents(); _updateStatistics( _currentFrame ); _releaseObjects(); EQLOG( co::base::LOG_ANY ) << "-- Finished All Frames --" << std::endl; return _currentFrame; }
//--------------------------------------------------------------------------- // identifier master node mapping //--------------------------------------------------------------------------- NodeID ObjectStore::_findMasterNodeID( const base::UUID& identifier ) { EQ_TS_NOT_THREAD( _commandThread ); // OPT: look up locally first? Nodes nodes; _localNode->getNodes( nodes ); // OPT: send to multiple nodes at once? for( Nodes::iterator i = nodes.begin(); i != nodes.end(); i++ ) { NodePtr node = *i; EQLOG( LOG_OBJECTS ) << "Finding " << identifier << " on " << node << std::endl; NodeFindMasterNodeIDPacket packet; packet.requestID = _localNode->registerRequest(); packet.identifier = identifier; node->send( packet ); NodeID masterNodeID = base::UUID::ZERO; _localNode->waitRequest( packet.requestID, masterNodeID ); if( masterNodeID != base::UUID::ZERO ) { EQLOG( LOG_OBJECTS ) << "Found " << identifier << " on " << masterNodeID << std::endl; return masterNodeID; } } return base::UUID::ZERO; }
//--------------------------------------------------------------------------- // command handlers //--------------------------------------------------------------------------- bool UnbufferedMasterCM::_cmdCommit( Command& command ) { EQ_TS_THREAD( _cmdThread ); LocalNodePtr localNode = _object->getLocalNode(); const ObjectCommitPacket* packet = command.get<ObjectCommitPacket>(); #if 0 EQLOG( LOG_OBJECTS ) << "commit v" << _version << " " << command << std::endl; #endif if( _slaves.empty( )) { localNode->serveRequest( packet->requestID, _version ); return true; } ObjectDeltaDataOStream os( this ); os.enableCommit( _version + 1, _slaves ); _object->pack( os ); os.disable(); if( os.hasSentData( )) { ++_version; EQASSERT( _version != VERSION_NONE ); #if 0 EQLOG( LOG_OBJECTS ) << "Committed v" << _version << ", id " << _object->getID() << std::endl; #endif } localNode->serveRequest( packet->requestID, _version ); return true; }
bool Channel::update( const uint128_t& frameID, const uint32_t frameNumber ) { if( !isRunning( )) return false; // not updated EQASSERT( isActive( )) EQASSERT( getWindow()->isActive( )); ChannelFrameStartPacket startPacket; startPacket.frameNumber = frameNumber; startPacket.version = getVersion(); _setupRenderContext( frameID, startPacket.context ); send( startPacket ); EQLOG( LOG_TASKS ) << "TASK channel " << getName() << " start frame " << &startPacket << std::endl; bool updated = false; const Compounds& compounds = getCompounds(); for( Compounds::const_iterator i = compounds.begin(); i != compounds.end(); ++i ) { const Compound* compound = *i; ChannelUpdateVisitor visitor( this, frameID, frameNumber ); visitor.setEye( EYE_CYCLOP ); compound->accept( visitor ); visitor.setEye( EYE_LEFT ); compound->accept( visitor ); visitor.setEye( EYE_RIGHT ); compound->accept( visitor ); updated |= visitor.isUpdated(); } ChannelFrameFinishPacket finishPacket; finishPacket.frameNumber = frameNumber; finishPacket.context = startPacket.context; send( finishPacket ); EQLOG( LOG_TASKS ) << "TASK channel " << getName() << " finish frame " << &finishPacket << std::endl; _lastDrawCompound = 0; return updated; }
void ObjectStore::_attachObject( Object* object, const base::UUID& id, const uint32_t inInstanceID ) { EQASSERT( object ); EQ_TS_THREAD( _receiverThread ); uint32_t instanceID = inInstanceID; if( inInstanceID == EQ_INSTANCE_INVALID ) instanceID = _genNextID( _instanceIDs ); object->attach( id, instanceID ); { base::ScopedMutex< base::SpinLock > mutex( _objects ); Objects& objects = _objects.data[ id ]; EQASSERTINFO( !object->isMaster() || objects.empty(), "Attaching master " << *object << ", " << objects.size() << " attached objects with same ID, first is: " << *objects[0] ); objects.push_back( object ); } _localNode->flushCommands(); // redispatch pending commands EQLOG( LOG_OBJECTS ) << "attached " << *object << " @" << static_cast< void* >( object ) << std::endl; }
uint128_t FullMasterCM::commit( const uint32_t incarnation ) { Mutex mutex( _slaves ); #if 0 EQLOG( LOG_OBJECTS ) << "commit v" << _version << " " << command << std::endl; #endif EQASSERT( _version != VERSION_NONE ); _updateCommitCount( incarnation ); if( _object->isDirty( )) { InstanceData* instanceData = _newInstanceData(); instanceData->os.enableCommit( _version + 1, *_slaves ); _object->getInstanceData( instanceData->os ); instanceData->os.disable(); if( instanceData->os.hasSentData( )) { ++_version; EQASSERT( _version != VERSION_NONE ); #if 0 EQINFO << "Committed v" << _version << "@" << _commitCount << ", id " << _object->getID() << std::endl; #endif _addInstanceData( instanceData ); } else _instanceDataCache.push_back( instanceData ); } _obsolete(); return _version; }
void LoadEqualizer::_assign( Compound* compound, const Viewport& vp, const Range& range ) { EQASSERTINFO( vp == Viewport::FULL || range == Range::ALL, "Mixed 2D/DB load-balancing not implemented" ); compound->setViewport( vp ); compound->setRange( range ); EQLOG( LOG_LB2 ) << compound->getChannel()->getName() << " set " << vp << ", " << range << std::endl; // save data for later use Data data; data.vp = vp; data.range = range; data.channel = compound->getChannel(); data.taskID = compound->getTaskID(); const Compound* destCompound = getCompound(); if( destCompound->getChannel() == compound->getChannel( )) data.destTaskID = destCompound->getTaskID(); EQASSERT( data.taskID > 0 ); if( !vp.hasArea() || !range.hasData( )) // will not render data.time = 0; LBFrameData& frameData = _history.back(); LBDatas& items = frameData.second; items.push_back( data ); }
uint32_t ObjectStore::mapObjectNB( Object* object, const base::UUID& id, const uint128_t& version, NodePtr master ) { if( !master || !master->isConnected( )) { EQWARN << "Mapping of object " << id << " failed, invalid master node" << std::endl; return EQ_UNDEFINED_UINT32; } NodeMapObjectPacket packet; packet.requestID = _localNode->registerRequest( object ); packet.objectID = id; packet.requestedVersion = version; packet.instanceID = _genNextID( _instanceIDs ); if( _instanceCache ) { const InstanceCache::Data& cached = (*_instanceCache)[ id ]; if( cached != InstanceCache::Data::NONE ) { const ObjectDataIStreamDeque& versions = cached.versions; EQASSERT( !cached.versions.empty( )); packet.useCache = true; packet.masterInstanceID = cached.masterInstanceID; packet.minCachedVersion = versions.front()->getVersion(); packet.maxCachedVersion = versions.back()->getVersion(); EQLOG( LOG_OBJECTS ) << "Object " << id << " have v" << packet.minCachedVersion << ".." << packet.maxCachedVersion << std::endl; } } master->send( packet ); return packet.requestID; }
void ObjectStore::_detachObject( Object* object ) { // check also _cmdUnmapObject when modifying! EQASSERT( object ); EQ_TS_THREAD( _receiverThread ); if( !object->isAttached() ) return; const base::UUID& id = object->getID(); EQASSERT( _objects->find( id ) != _objects->end( )); EQLOG( LOG_OBJECTS ) << "Detach " << *object << std::endl; Objects& objects = _objects.data[ id ]; Objects::iterator i = find( objects.begin(),objects.end(), object ); EQASSERT( i != objects.end( )); { base::ScopedMutex< base::SpinLock > mutex( _objects ); objects.erase( i ); if( objects.empty( )) _objects->erase( id ); } EQASSERT( object->getInstanceID() != EQ_INSTANCE_INVALID ); object->detach(); return; }
void ObjectStore::swapObject( Object* oldObject, Object* newObject ) { EQASSERT( newObject ); EQASSERT( oldObject ); EQASSERT( oldObject->isMaster() ); EQ_TS_THREAD( _receiverThread ); if( !oldObject->isAttached() ) return; EQLOG( LOG_OBJECTS ) << "Swap " << base::className( oldObject ) <<std::endl; const base::UUID& id = oldObject->getID(); base::ScopedMutex< base::SpinLock > mutex( _objects ); ObjectsHash::iterator i = _objects->find( id ); EQASSERT( i != _objects->end( )); if( i == _objects->end( )) return; Objects& objects = i->second; Objects::iterator j = find( objects.begin(), objects.end(), oldObject ); EQASSERT( j != objects.end( )); if( j == objects.end( )) return; newObject->transfer( oldObject ); *j = newObject; }
void LoadEqualizer::_computeSplit() { EQASSERT( !_history.empty( )); const LBFrameData& frameData = _history.front(); const Compound* compound = getCompound(); EQLOG( LOG_LB2 ) << "----- balance " << compound->getChannel()->getName() << " using frame " << frameData.first << " tree " << std::endl << _tree; // sort load items for each of the split directions LBDatas items( frameData.second ); _removeEmpty( items ); LBDatas sortedData[3] = { items, items, items }; if( _mode == MODE_DB ) { LBDatas& rangeData = sortedData[ MODE_DB ]; sort( rangeData.begin(), rangeData.end(), _compareRange ); } else { LBDatas& xData = sortedData[ MODE_VERTICAL ]; sort( xData.begin(), xData.end(), _compareX ); LBDatas& yData = sortedData[ MODE_HORIZONTAL ]; sort( yData.begin(), yData.end(), _compareY ); #ifndef NDEBUG for( LBDatas::const_iterator i = xData.begin(); i != xData.end(); ++i ) { const Data& data = *i; EQLOG( LOG_LB2 ) << " " << data.vp << ", time " << data.time << " (+" << data.assembleTime << ")" << std::endl; } #endif } const float time = float( _getTotalTime( )); EQLOG( LOG_LB2 ) << "Render time " << time << " for " << _tree->resources << " resources" << std::endl; _computeSplit( _tree, time, sortedData, Viewport(), Range( )); }
//--------------------------------------------------------------------------- // exit //--------------------------------------------------------------------------- void Channel::configExit() { EQASSERT( _state == STATE_RUNNING || _state == STATE_INIT_FAILED ); _state = STATE_EXITING; EQLOG( LOG_INIT ) << "Exit channel" << std::endl; ChannelConfigExitPacket packet; send( packet ); }
//--------------------------------------------------------------------------- // init //--------------------------------------------------------------------------- void Pipe::configInit( const uint128_t& initID, const uint32_t frameNumber ) { EQASSERT( _state == STATE_STOPPED ); _state = STATE_INITIALIZING; EQLOG( LOG_INIT ) << "Create pipe" << std::endl; NodeCreatePipePacket createPipePacket; createPipePacket.objectID = getNode()->getID(); createPipePacket.pipeID = getID(); createPipePacket.threaded = getIAttribute( IATTR_HINT_THREAD ); getNode()->send( createPipePacket ); EQLOG( LOG_INIT ) << "Init pipe" << std::endl; PipeConfigInitPacket packet; packet.initID = initID; packet.frameNumber = frameNumber; send( packet ); }
//=========================================================================== // Operations //=========================================================================== //--------------------------------------------------------------------------- // init //--------------------------------------------------------------------------- void Window::configInit( const uint128_t& initID, const uint32_t frameNumber ) { EQASSERT( !needsDelete( )); EQASSERT( _state == STATE_STOPPED ); _state = STATE_INITIALIZING; EQLOG( LOG_INIT ) << "Create Window" << std::endl; PipeCreateWindowPacket createWindowPacket; createWindowPacket.windowID = getID(); getPipe()->send( createWindowPacket ); WindowConfigInitPacket packet; packet.initID = initID; EQLOG( LOG_INIT ) << "Init Window" << std::endl; send( packet ); EQLOG( LOG_TASKS ) << "TASK window configInit " << &packet << std::endl; }
void TreeEqualizer::_split( Node* node ) { if( node->compound ) return; EQASSERT( node->left && node->right ); Node* left = node->left; Node* right = node->right; // easy outs if( left->resources == 0.f ) { node->split = 0.f; return; } if( right->resources == 0.f ) { node->split = 1.f; return; } // new split const float target = node->time * left->resources / node->resources; const float leftTime = float(left->time); float split = 0.f; const float rightTime = float(right->time); if( leftTime >= target ) split = target / leftTime * node->split; else { const float timeLeft = target - leftTime; split = node->split + timeLeft / rightTime * ( 1.f - node->split ); } EQLOG( LOG_LB2 ) << "Should split at " << split << " (" << target << ": " << leftTime << " by " << left->resources << "/" << rightTime << " by " << right->resources << ")" << std::endl; node->split = (1.f - _damping) * split + _damping * node->split; EQLOG( LOG_LB2 ) << "Dampened split at " << node->split << std::endl; _split( left ); _split( right ); }
//--------------------------------------------------------------------------- // update //--------------------------------------------------------------------------- void Window::updateDraw( const uint128_t& frameID, const uint32_t frameNumber ) { if( !isRunning( )) return; EQASSERT( isActive( )) WindowFrameStartPacket startPacket; startPacket.frameID = frameID; startPacket.frameNumber = frameNumber; startPacket.version = getVersion(); send( startPacket ); EQLOG( LOG_TASKS ) << "TASK window start frame " << &startPacket << std::endl; const Channels& channels = getChannels(); _swap = false; for( ChannelsCIter i = channels.begin(); i != channels.end(); ++i ) { Channel* channel = *i; if( channel->update( frameID, frameNumber )) _swap = true; } if( !_lastDrawChannel ) // no FrameDrawFinish sent { WindowFrameDrawFinishPacket drawFinishPacket; drawFinishPacket.frameNumber = frameNumber; drawFinishPacket.frameID = frameID; send( drawFinishPacket ); EQLOG( LOG_TASKS ) << "TASK window draw finish " << getName() << " " << &drawFinishPacket << std::endl; } _lastDrawChannel = 0; if( _swapFinish ) { WindowFinishPacket packet; send( packet ); EQLOG( LOG_TASKS ) << "TASK finish " << &packet << std::endl; _swapFinish = false; } }
void Window::activate() { Pipe* pipe = getPipe(); EQASSERT( pipe ); ++_active; pipe->activate(); EQLOG( LOG_VIEW ) << "activate: " << _active << std::endl; }
bool Channel::_cmdConfigExitReply( co::Command& command ) { const ChannelConfigExitReplyPacket* packet = command.get<ChannelConfigExitReplyPacket>(); EQLOG( LOG_INIT ) << "handle channel configExit reply " << packet << std::endl; _state = packet->result ? STATE_EXIT_SUCCESS : STATE_EXIT_FAILED; return true; }
//--------------------------------------------------------------------------- // update //--------------------------------------------------------------------------- void Pipe::update( const uint128_t& frameID, const uint32_t frameNumber ) { if( !isRunning( )) return; EQASSERT( isActive( )) PipeFrameStartClockPacket startClockPacket; send( startClockPacket ); PipeFrameStartPacket startPacket; startPacket.frameID = frameID; startPacket.frameNumber = frameNumber; startPacket.version = getVersion(); send( startPacket ); EQLOG( LOG_TASKS ) << "TASK pipe start frame " << &startPacket << std::endl; const Windows& windows = getWindows(); for( Windows::const_iterator i = windows.begin(); i != windows.end(); ++i ) (*i)->updateDraw( frameID, frameNumber ); for( Windows::const_iterator i = windows.begin(); i != windows.end(); ++i ) (*i)->updatePost( frameID, frameNumber ); if( !_lastDrawWindow ) // no FrameDrawFinish sent { PipeFrameDrawFinishPacket drawFinishPacket; drawFinishPacket.frameNumber = frameNumber; drawFinishPacket.frameID = frameID; send( drawFinishPacket ); EQLOG( LOG_TASKS ) << "TASK pipe draw finish " << getName() << " " << &drawFinishPacket << std::endl; } _lastDrawWindow = 0; PipeFrameFinishPacket finishPacket; finishPacket.frameID = frameID; finishPacket.frameNumber = frameNumber; send( finishPacket ); EQLOG( LOG_TASKS ) << "TASK pipe finish frame " << &finishPacket << std::endl; }
void Pipe::activate() { Node* node = getNode(); EQASSERT( node ); ++_active; if( node ) node->activate(); EQLOG( LOG_VIEW ) << "activate: " << _active << std::endl; }
void Window::deactivate() { EQASSERT( _active != 0 ); Pipe* pipe = getPipe(); EQASSERT( pipe ); --_active; pipe->deactivate(); EQLOG( LOG_VIEW ) << "deactivate: " << _active << std::endl; };
void Channel::activate() { Window* window = getWindow(); EQASSERT( window ); ++_active; window->activate(); EQLOG( LOG_VIEW ) << "activate: " << _active << " " << (void*)this << std::endl; }
void Channel::deactivate() { Window* window = getWindow(); EQASSERT( _active != 0 ); EQASSERT( window ); --_active; window->deactivate(); EQLOG( LOG_VIEW ) << "deactivate: " << _active << " " << (void*)this << std::endl; }
void Object::attach( const base::UUID& id, const uint32_t instanceID ) { EQASSERT( !isAttached() ); EQASSERT( _localNode ); EQASSERT( instanceID <= EQ_INSTANCE_MAX ); _id = id; _instanceID = instanceID; EQLOG( LOG_OBJECTS ) << _id << '.' << _instanceID << ": " << base::className( this ) << (isMaster() ? " master" : " slave") << std::endl; }
uint32_t Config::finishFrame() { ClientPtr client = getClient(); const uint32_t latency = getLatency(); const uint32_t frameToFinish = (_currentFrame >= latency) ? _currentFrame - latency : 0; ConfigStatistics stat( Statistic::CONFIG_FINISH_FRAME, this ); stat.event.data.statistic.frameNumber = frameToFinish; { ConfigStatistics waitStat( Statistic::CONFIG_WAIT_FINISH_FRAME, this ); waitStat.event.data.statistic.frameNumber = frameToFinish; // local draw sync if( _needsLocalSync( )) while( _unlockedFrame < _currentFrame ) client->processCommand(); // local node finish (frame-latency) sync const Nodes& nodes = getNodes(); if( !nodes.empty( )) { EQASSERT( nodes.size() == 1 ); const Node* node = nodes.front(); while( node->getFinishedFrame() < frameToFinish ) client->processCommand(); } // global sync const uint32_t timeout = getTimeout(); co::base::Clock time; const int64_t pingTimeout = co::Global::getKeepaliveTimeout(); while( !_finishedFrame.timedWaitGE( frameToFinish, pingTimeout )) { if( time.getTime64() >= timeout || !getLocalNode()->pingIdleNodes()) { EQWARN << "Timeout waiting for nodes to finish frame " << frameToFinish << std::endl; break; } } } handleEvents(); _updateStatistics( frameToFinish ); _releaseObjects(); EQLOG( co::base::LOG_ANY ) << "---- Finished Frame --- " << frameToFinish << " (" << _currentFrame << ')' << std::endl; return frameToFinish; }
ObjectDataOStream::ObjectDataOStream( const ObjectCM* cm ) : _cm( cm ) , _version( VERSION_INVALID ) , _sequence( 0 ) { const Object* object = cm->getObject(); const uint32_t name = object->chooseCompressor(); _initCompressor( name ); EQLOG( LOG_OBJECTS ) << "Using byte compressor 0x" << std::hex << name << std::dec << " for " << base::className( object ) << std::endl; }
//--------------------------------------------------------------------------- // exit //--------------------------------------------------------------------------- void Pipe::configExit() { if( _state == STATE_EXITING ) return; EQASSERT( _state == STATE_RUNNING || _state == STATE_INIT_FAILED ); _state = STATE_EXITING; EQLOG( LOG_INIT ) << "Exit pipe" << std::endl; PipeConfigExitPacket packet; send( packet ); }
//--------------------------------------------------------------------------- // exit //--------------------------------------------------------------------------- void Window::configExit() { if( _state & STATE_EXITING ) return; EQASSERT( isRunning() || _state == STATE_INIT_FAILED ); _state = State( needsDelete() ? STATE_EXITING | STATE_DELETE : STATE_EXITING ); EQLOG( LOG_INIT ) << "Exit Window" << std::endl; WindowConfigExitPacket packet; send( packet ); }
void Pipe::deactivate() { EQASSERT( _active != 0 ); Node* node = getNode(); EQASSERT( node ); --_active; if( node ) node->deactivate(); EQLOG( LOG_VIEW ) << "deactivate: " << _active << std::endl; };
//--------------------------------------------------------------------------- // init //--------------------------------------------------------------------------- void Channel::configInit( const uint128_t& initID, const uint32_t frameNumber ) { EQASSERT( _state == STATE_STOPPED ); _state = STATE_INITIALIZING; WindowCreateChannelPacket createChannelPacket( getID( )); getWindow()->send( createChannelPacket ); ChannelConfigInitPacket packet; packet.initID = initID; EQLOG( LOG_INIT ) << "Init channel" << std::endl; send( packet ); }