LCOV - code coverage report
Current view: top level - eq/server/equalizers - viewEqualizer.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 21 388 5.4 %
Date: 2014-06-18 Functions: 8 53 15.1 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2009-2013, Stefan Eilemann <eile@equalizergraphics.com>
       3             :  *
       4             :  * This library is free software; you can redistribute it and/or modify it under
       5             :  * the terms of the GNU Lesser General Public License version 2.1 as published
       6             :  * by the Free Software Foundation.
       7             :  *
       8             :  * This library is distributed in the hope that it will be useful, but WITHOUT
       9             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      10             :  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      11             :  * details.
      12             :  *
      13             :  * You should have received a copy of the GNU Lesser General Public License
      14             :  * along with this library; if not, write to the Free Software Foundation, Inc.,
      15             :  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      16             :  */
      17             : 
      18             : #include "viewEqualizer.h"
      19             : 
      20             : #include "../compound.h"
      21             : #include "../compoundVisitor.h"
      22             : #include "../config.h"
      23             : #include "../log.h"
      24             : #include "../pipe.h"
      25             : 
      26             : #include <eq/client/statistic.h>
      27             : 
      28             : #include <set>
      29             : 
      30             : #define MIN_USAGE .1f // 10%
      31             : 
      32             : namespace eq
      33             : {
      34             : namespace server
      35             : {
      36             : 
      37          16 : ViewEqualizer::ViewEqualizer()
      38          16 :         : _nPipes( 0 )
      39             : {
      40          16 :     LBINFO << "New view equalizer @" << (void*)this << std::endl;
      41          16 : }
      42             : 
      43           0 : ViewEqualizer::ViewEqualizer( const ViewEqualizer& from )
      44             :         : Equalizer( from )
      45           0 :         , _nPipes( 0 )
      46           0 : {}
      47             : 
      48          48 : ViewEqualizer::~ViewEqualizer()
      49             : {
      50          16 :     attach( 0 );
      51          16 :     LBINFO << "Delete view equalizer @" << (void*)this << std::endl;
      52          32 : }
      53             : 
      54           0 : ViewEqualizer::Listener::Listener()
      55             : {
      56           0 : }
      57             : 
      58           0 : ViewEqualizer::Listener::~Listener()
      59             : {
      60           0 : }
      61             : 
      62          48 : void ViewEqualizer::attach( Compound* compound )
      63             : {
      64          48 :     for( Listeners::iterator i =_listeners.begin(); i != _listeners.end(); ++i )
      65           0 :         (*i).clear();
      66             : 
      67          48 :     _listeners.clear();
      68          48 :     Equalizer::attach( compound );
      69          48 : }
      70             : 
      71           0 : void ViewEqualizer::notifyUpdatePre( Compound* compound LB_UNUSED,
      72             :                                      const uint32_t frameNumber )
      73             : {
      74           0 :     LBASSERT( compound == getCompound( ));
      75             : 
      76           0 :     _updateListeners();
      77           0 :     _updateResources();
      78           0 :     _update( frameNumber );
      79           0 : }
      80             : 
      81             : namespace
      82             : {
      83           0 : class SelfAssigner : public CompoundVisitor
      84             : {
      85             : public:
      86           0 :     SelfAssigner( const Pipe* self, float& nResources,
      87             :                   lunchbox::PtrHash< Pipe*, float >& pipeUsage )
      88             :             : _self( self ), _nResources( nResources ), _pipeUsage( pipeUsage )
      89           0 :             , _numChannels( 0 ) {}
      90             : 
      91           0 :     virtual VisitorResult visitLeaf( Compound* compound )
      92             :         {
      93           0 :             if( !compound->isActive( ))
      94           0 :                 return TRAVERSE_CONTINUE;
      95             : 
      96           0 :             Pipe* pipe = compound->getPipe();
      97           0 :             LBASSERT( pipe );
      98             : 
      99           0 :             if( pipe != _self )
     100           0 :                 return TRAVERSE_CONTINUE;
     101             : 
     102           0 :             if( _pipeUsage.find( pipe ) == _pipeUsage.end( ))
     103           0 :                 _pipeUsage[ pipe ] = 0.0f;
     104             : 
     105           0 :             float& pipeUsage = _pipeUsage[ pipe ];
     106           0 :             if( pipeUsage >= 1.0f )
     107             :             {
     108           0 :                 compound->setUsage( 0.f );
     109           0 :                 return TRAVERSE_TERMINATE;
     110             :             }
     111             : 
     112           0 :             if( pipeUsage > 0.0f ) // pipe already partly used
     113             :             {
     114           0 :                 LBASSERT( pipeUsage < 1.0f );
     115             : 
     116           0 :                 float use = 1.0f - pipeUsage;
     117           0 :                 use = LB_MAX( use, MIN_USAGE );
     118             : 
     119           0 :                 compound->setUsage( use );
     120           0 :                 _nResources -= use;
     121           0 :                 pipeUsage = 1.0f; // Don't use more than twice
     122           0 :                 LBLOG( LOG_LB1 ) << "  Use "
     123           0 :                                 << static_cast< unsigned >( use * 100.f + .5f )
     124           0 :                                 << "% of " << pipe->getName() << " task "
     125           0 :                                 << compound->getTaskID() << ", "
     126           0 :                                 << _nResources * 100.f << "% left" << std::endl;
     127             :             }
     128             :             else
     129             :             {
     130           0 :                 LBASSERT( pipeUsage == 0.0f );
     131             : 
     132           0 :                 float use = LB_MIN( 1.0f, _nResources );
     133             : 
     134           0 :                 compound->setUsage( use );
     135           0 :                 _nResources -= use;
     136           0 :                 pipeUsage = use;
     137           0 :                 LBLOG( LOG_LB1 ) << "  Use "
     138           0 :                                 << static_cast< unsigned >( use * 100.f + .5f )
     139           0 :                                 << "% of " << pipe->getName() << " task "
     140           0 :                                 << compound->getTaskID() << ", "
     141           0 :                                 << _nResources * 100.f << "% left" << std::endl;
     142             :             }
     143           0 :             ++_numChannels;
     144             : 
     145           0 :             return TRAVERSE_TERMINATE;
     146             :         }
     147             : 
     148           0 :     uint32_t getNumChannels() const { return _numChannels; }
     149             : 
     150             : private:
     151             :     const Pipe* const _self;
     152             :     float& _nResources;
     153             :     lunchbox::PtrHash< Pipe*, float >& _pipeUsage;
     154             :     uint32_t _numChannels;
     155             : };
     156             : 
     157           0 : class PreviousAssigner : public CompoundVisitor
     158             : {
     159             : public:
     160           0 :     PreviousAssigner( const Pipe* self, float& nResources,
     161             :                       lunchbox::PtrHash< Pipe*, float >& pipeUsage )
     162             :             : _self( self ), _nResources( nResources ), _pipeUsage( pipeUsage )
     163           0 :             , _numChannels( 0 ) {}
     164             : 
     165           0 :     virtual VisitorResult visitLeaf( Compound* compound )
     166             :         {
     167           0 :             if( !compound->isActive( ))
     168           0 :                 return TRAVERSE_CONTINUE;
     169             : 
     170           0 :             Pipe* pipe = compound->getPipe();
     171           0 :             LBASSERT( pipe );
     172             : 
     173           0 :             if( compound->getUsage() == 0.0f || // not previously used
     174           0 :                 pipe == _self)                  // already assigned above
     175             :             {
     176           0 :                 return TRAVERSE_CONTINUE;
     177             :             }
     178             : 
     179           0 :             compound->setUsage( 0.0f ); // reset to unused
     180           0 :             if( _nResources <= MIN_USAGE ) // done
     181           0 :                 return TRAVERSE_CONTINUE;
     182             : 
     183           0 :             if( _pipeUsage.find( pipe ) == _pipeUsage.end( ))
     184           0 :                 _pipeUsage[ pipe ] = 0.0f;
     185             : 
     186           0 :             float& pipeUsage = _pipeUsage[ pipe ];
     187           0 :             if( pipeUsage > 0.0f ) // pipe already partly used
     188           0 :                 return TRAVERSE_CONTINUE;
     189             : 
     190           0 :             float use = LB_MIN( 1.0f, _nResources );
     191           0 :             if( use + MIN_USAGE > 1.0f )
     192           0 :                 use = 1.0f;
     193             : 
     194           0 :             pipeUsage = use;
     195           0 :             compound->setUsage( use );
     196           0 :             _nResources -= use;
     197           0 :             ++_numChannels;
     198             : 
     199           0 :             LBLOG( LOG_LB1 ) << "  Use "
     200           0 :                             << static_cast< unsigned >( use * 100.f + .5f )
     201           0 :                             << "% of " << pipe->getName() << " task "
     202           0 :                             << compound->getTaskID() << ", "
     203           0 :                             << _nResources * 100.f << "% left" << std::endl;
     204           0 :             return TRAVERSE_CONTINUE;
     205             :         }
     206             : 
     207           0 :     uint32_t getNumChannels() const { return _numChannels; }
     208             : 
     209             : private:
     210             :     const Pipe* const _self;
     211             :     float& _nResources;
     212             :     lunchbox::PtrHash< Pipe*, float >& _pipeUsage;
     213             :     uint32_t _numChannels;
     214             : };
     215             : 
     216           0 : class NewAssigner : public CompoundVisitor
     217             : {
     218             : public:
     219           0 :     NewAssigner( float& nResources,
     220             :                  lunchbox::PtrHash< Pipe*, float >& pipeUsage )
     221             :             : _nResources( nResources ), _pipeUsage( pipeUsage )
     222             :             , _numChannels( 0 )
     223           0 :             , _fallback( 0 ) {}
     224             : 
     225           0 :     virtual VisitorResult visitLeaf( Compound* compound )
     226             :         {
     227           0 :             if( !compound->isActive( ))
     228           0 :                 return TRAVERSE_CONTINUE;
     229             : 
     230           0 :             if( !_fallback )
     231           0 :                 _fallback = compound;
     232             : 
     233           0 :             if( compound->getUsage() != 0.0f ) // already used
     234           0 :                 return TRAVERSE_CONTINUE;
     235             : 
     236           0 :             Pipe* pipe = compound->getPipe();
     237           0 :             LBASSERT( pipe );
     238             : 
     239           0 :             if( _pipeUsage.find( pipe ) == _pipeUsage.end( ))
     240           0 :                 _pipeUsage[ pipe ] = 0.0f;
     241             : 
     242           0 :             float& pipeUsage = _pipeUsage[ pipe ];
     243           0 :             if( pipeUsage >= 1.0f )
     244           0 :                 return TRAVERSE_CONTINUE;
     245             : 
     246           0 :             if( pipeUsage > 0.0f ) // pipe already partly used
     247             :             {
     248           0 :                 LBASSERT( pipeUsage < 1.0f );
     249             : 
     250           0 :                 float use = 1.0f - pipeUsage;
     251           0 :                 use = LB_MAX( use, MIN_USAGE );
     252             : 
     253           0 :                 compound->setUsage( use );
     254           0 :                 _nResources -= use;
     255           0 :                 pipeUsage = 1.0f; // Don't use more than twice
     256           0 :                 LBLOG( LOG_LB1 ) << "  Use "
     257           0 :                                 << static_cast< unsigned >( use * 100.f + .5f )
     258           0 :                                 << "% of " << pipe->getName() << " task "
     259           0 :                                 << compound->getTaskID() << ", "
     260           0 :                                 << _nResources * 100.f << "% left" << std::endl;
     261             :             }
     262             :             else
     263             :             {
     264           0 :                 LBASSERT( pipeUsage == 0.0f );
     265             : 
     266           0 :                 float use = LB_MIN( 1.0f, _nResources );
     267             : 
     268           0 :                 compound->setUsage( use );
     269           0 :                 _nResources -= use;
     270           0 :                 pipeUsage = use;
     271           0 :                 LBLOG( LOG_LB1 ) << "  Use "
     272           0 :                                 << static_cast< unsigned >( use * 100.f + .5f )
     273           0 :                                 << "% of " << pipe->getName() << " task "
     274           0 :                                 << compound->getTaskID() << ", "
     275           0 :                                 << _nResources * 100.f << "% left" << std::endl;
     276             :             }
     277           0 :             ++_numChannels;
     278             : 
     279           0 :             if( _nResources <= MIN_USAGE )
     280           0 :                 return TRAVERSE_TERMINATE; // done
     281           0 :             return TRAVERSE_CONTINUE;
     282             :         }
     283             : 
     284           0 :     uint32_t getNumChannels() const { return _numChannels; }
     285           0 :     Compound* getFallback() { return _fallback; }
     286             : 
     287             : private:
     288             :     float& _nResources;
     289             :     lunchbox::PtrHash< Pipe*, float >& _pipeUsage;
     290             :     uint32_t _numChannels;
     291             :     Compound* _fallback;
     292             : };
     293             : 
     294             : }
     295             : 
     296           0 : void ViewEqualizer::_update( const uint32_t frameNumber )
     297             : {
     298           0 :     const uint32_t frame = _findInputFrameNumber();
     299           0 :     LBLOG( LOG_LB1 ) << "Using data from frame " << frame << std::endl;
     300             : 
     301             :     //----- Gather data for frame
     302           0 :     Loads loads;
     303           0 :     int64_t totalTime( 0 );
     304             : 
     305           0 :     for( Listeners::iterator i =_listeners.begin(); i != _listeners.end(); ++i )
     306             :     {
     307           0 :         Listener& listener = *i;
     308           0 :         const Listener::Load& load = listener.useLoad( frame );
     309             : 
     310           0 :         totalTime += load.time;
     311           0 :         loads.push_back( load );
     312             :     }
     313             : 
     314           0 :     const Compound* compound = getCompound();
     315             : 
     316           0 :     if( isFrozen() || !compound->isActive() || _nPipes == 0 )
     317             :         // always execute code above to not leak memory
     318           0 :         return;
     319             : 
     320           0 :     if( totalTime == 0 ) // no data
     321           0 :         totalTime = 1;
     322             : 
     323           0 :     const float resourceTime( static_cast< float >( totalTime ) /
     324           0 :                               static_cast< float >( _nPipes ));
     325           0 :     LBLOG( LOG_LB1 ) << resourceTime << "ms/resource" << std::endl;
     326             : 
     327             :     //----- Assign new resource usage
     328           0 :     const Compounds& children = compound->getChildren();
     329           0 :     const size_t size( _listeners.size( ));
     330           0 :     LBASSERT( children.size() == size );
     331           0 :     lunchbox::PtrHash< Pipe*, float > pipeUsage;
     332           0 :     float* leftOvers = static_cast< float* >( alloca( size * sizeof( float )));
     333             : 
     334             :     // use self
     335           0 :     for( size_t i = 0; i < size; ++i )
     336             :     {
     337           0 :         Listener::Load& load = loads[ i ];
     338           0 :         LBASSERT( load.missing == 0 );
     339             : 
     340           0 :         Compound* child = children[ i ];
     341           0 :         if( !child->isActive( ))
     342           0 :             continue;
     343             : 
     344           0 :         float segmentResources( load.time / resourceTime );
     345             : 
     346           0 :         LBLOG( LOG_LB1 ) << "----- balance step 1 for view " << i << " ("
     347           0 :                          << child->getChannel()->getName() << " "
     348           0 :                          << child->getChannel()->getSerial() << ") using "
     349           0 :                          << segmentResources << " resources" << std::endl;
     350           0 :         SelfAssigner assigner( child->getPipe(), segmentResources, pipeUsage );
     351             : 
     352           0 :         child->accept( assigner );
     353           0 :         load.missing = assigner.getNumChannels();
     354           0 :         leftOvers[ i ] = segmentResources;
     355           0 :     }
     356             : 
     357             :     // use previous' frames resources
     358           0 :     for( size_t i = 0; i < size; ++i )
     359             :     {
     360           0 :         Listener::Load& load = loads[ i ];
     361           0 :         Compound* child = children[ i ];
     362           0 :         if( !child->isActive( ))
     363           0 :             continue;
     364             : 
     365           0 :         float& leftOver = leftOvers[i];
     366           0 :         LBLOG( LOG_LB1 ) << "----- balance step 2 for view " << i << " ("
     367           0 :                          << child->getChannel()->getName() << " "
     368           0 :                          << child->getChannel()->getSerial() << ") using "
     369           0 :                          << leftOver << " resources" << std::endl;
     370           0 :         PreviousAssigner assigner( child->getPipe(), leftOver, pipeUsage );
     371             : 
     372           0 :         child->accept( assigner );
     373           0 :         load.missing += assigner.getNumChannels();
     374           0 :     }
     375             : 
     376             :     // satisfy left-overs
     377           0 :     for( size_t i = 0; i < size; ++i )
     378             :     {
     379           0 :         Listener& listener = _listeners[ i ];
     380           0 :         LBASSERTINFO( listener.getNLoads() <= getConfig()->getLatency() + 3,
     381             :                       listener );
     382             : 
     383           0 :         float& leftOver = leftOvers[i];
     384           0 :         Listener::Load& load = loads[ i ];
     385           0 :         Compound* child = children[ i ];
     386             : 
     387           0 :         if( !child->isActive( ))
     388           0 :             continue;
     389             : 
     390           0 :         if( leftOver > MIN_USAGE || load.missing == 0 )
     391             :         {
     392           0 :             LBLOG( LOG_LB1 ) << "----- balance step 3 for view " << i << " ("
     393           0 :                             << child->getChannel()->getName() << ") using "
     394           0 :                             << leftOver << " resources" << std::endl;
     395             : 
     396           0 :             NewAssigner assigner( leftOver, pipeUsage );
     397           0 :             child->accept( assigner );
     398           0 :             load.missing += assigner.getNumChannels();
     399             : 
     400           0 :             if( load.missing == 0 ) // assign at least one resource
     401             :             {
     402           0 :                 Compound* fallback = assigner.getFallback();
     403           0 :                 LBASSERT( fallback );
     404           0 :                 LBASSERT( leftOver > 0 );
     405             : 
     406           0 :                 fallback->setUsage( leftOver );
     407           0 :                 load.missing = 1;
     408           0 :                 LBLOG( LOG_LB1 ) << "  Use "
     409           0 :                                 << static_cast< unsigned >( leftOver*100.f+.5f )
     410           0 :                                 << "% of " << fallback->getPipe()->getName()
     411           0 :                                 << " task " << fallback->getTaskID()
     412           0 :                                 << std::endl;
     413           0 :             }
     414             :         }
     415             : 
     416           0 :         listener.newLoad( frameNumber, load.missing );
     417           0 :     }
     418             : }
     419             : 
     420           0 : uint32_t ViewEqualizer::_findInputFrameNumber() const
     421             : {
     422           0 :     LBASSERT( !_listeners.empty( ));
     423             : 
     424           0 :     uint32_t frame = std::numeric_limits< uint32_t >::max();
     425           0 :     const Compound* compound = getCompound();
     426           0 :     const Compounds& children = compound->getChildren();
     427           0 :     const size_t nChildren = children.size();
     428           0 :     LBASSERT( nChildren == _listeners.size( ));
     429             : 
     430           0 :     bool change = true;
     431           0 :     while( change )
     432             :     {
     433           0 :         change = false;
     434           0 :         for( size_t i = 0; i < nChildren; ++i )
     435             :         {
     436           0 :             const Compound* child = children[ i ];
     437           0 :             if( !child->isActive( ))
     438           0 :                 continue;
     439             : 
     440           0 :             const Listener& listener = _listeners[ i ];
     441           0 :             const uint32_t youngest = listener.findYoungestLoad( frame );
     442           0 :             if( frame > youngest )
     443             :             {
     444           0 :                 change = true;
     445           0 :                 frame = youngest;
     446             :             }
     447             :         }
     448             :     }
     449             : 
     450           0 :     return frame;
     451             : }
     452             : 
     453             : 
     454           0 : void ViewEqualizer::_updateListeners()
     455             : {
     456           0 :     if( !_listeners.empty( ))
     457             :     {
     458           0 :         LBASSERT( getCompound()->getChildren().size() == _listeners.size( ));
     459           0 :         return;
     460             :     }
     461             : 
     462           0 :     Compound* compound = getCompound();
     463           0 :     const Compounds& children = compound->getChildren();
     464           0 :     const size_t nChildren = children.size();
     465             : 
     466           0 :     _listeners.resize( nChildren );
     467           0 :     for( size_t i = 0; i < nChildren; ++i )
     468             :     {
     469           0 :         LBLOG( LOG_LB1 ) << lunchbox::disableFlush << "Tasks for view " << i
     470           0 :                          << ": ";
     471           0 :         Listener& listener = _listeners[ i ];
     472           0 :         listener.update( children[i] );
     473           0 :         LBLOG(LOG_LB1) << std::endl << lunchbox::enableFlush;
     474             :     }
     475             : }
     476             : 
     477             : namespace
     478             : {
     479           0 : class PipeCounter : public CompoundVisitor
     480             : {
     481             : public:
     482           0 :     virtual VisitorResult visitPre( const Compound* compound )
     483           0 :         { return compound->isActive() ? TRAVERSE_CONTINUE : TRAVERSE_PRUNE; }
     484             : 
     485           0 :     virtual VisitorResult visitLeaf( const Compound* compound )
     486             :         {
     487           0 :             if( !compound->isActive( ))
     488           0 :                 return TRAVERSE_PRUNE;
     489             : 
     490           0 :             const Pipe* pipe = compound->getPipe();
     491           0 :             LBASSERT( pipe );
     492           0 :             _pipes.insert( pipe );
     493           0 :             return TRAVERSE_CONTINUE;
     494             :         }
     495             : 
     496           0 :     size_t getNPipes() const { return _pipes.size(); }
     497             : 
     498             : private:
     499             :     std::set< const Pipe* > _pipes;
     500             : };
     501             : }
     502             : 
     503           0 : void ViewEqualizer::_updateResources()
     504             : {
     505           0 :     PipeCounter counter;
     506           0 :     const Compound* compound = getCompound();
     507           0 :     compound->accept( counter );
     508           0 :     _nPipes = counter.getNPipes();
     509           0 : }
     510             : 
     511             : //---------------------------------------------------------------------------
     512             : // Per-child listener implementation
     513             : //---------------------------------------------------------------------------
     514             : namespace
     515             : {
     516           0 : class LoadSubscriber : public CompoundVisitor
     517             : {
     518             : public:
     519           0 :     LoadSubscriber( ChannelListener* listener,
     520             :                     lunchbox::PtrHash< Channel*, uint32_t >& taskIDs )
     521             :             : _listener( listener )
     522           0 :             , _taskIDs( taskIDs ) {}
     523             : 
     524           0 :     virtual VisitorResult visitLeaf( Compound* compound )
     525             :         {
     526           0 :             Channel* channel = compound->getChannel();
     527           0 :             LBASSERT( channel );
     528             : 
     529           0 :             if( _taskIDs.find( channel ) == _taskIDs.end( ))
     530             :             {
     531           0 :                 channel->addListener( _listener );
     532           0 :                 _taskIDs[ channel ] = compound->getTaskID();
     533           0 :                 LBLOG( LOG_LB1 ) << _taskIDs[ channel ] << ' ';
     534             :             }
     535             :             else
     536             :             {
     537           0 :                 LBASSERTINFO( 0,
     538             :                               "View equalizer does not support using channel "<<
     539             :                               channel->getName() <<
     540             :                               " multiple times in one branch" );
     541             :             }
     542           0 :             return TRAVERSE_CONTINUE;
     543             :         }
     544             : 
     545             : private:
     546             :     ChannelListener* const _listener;
     547             :     lunchbox::PtrHash< Channel*, uint32_t >& _taskIDs;
     548             : };
     549             : }
     550             : 
     551           0 : void ViewEqualizer::Listener::update( Compound* compound )
     552             : {
     553           0 :     LBASSERT( _taskIDs.empty( ));
     554           0 :     LoadSubscriber subscriber( this, _taskIDs );
     555           0 :     compound->accept( subscriber );
     556           0 : }
     557             : 
     558           0 : void ViewEqualizer::Listener::clear()
     559             : {
     560           0 :     for( TaskIDHash::const_iterator i = _taskIDs.begin();
     561           0 :          i != _taskIDs.end(); ++i )
     562             :     {
     563           0 :         i->first->removeListener( this );
     564             :     }
     565           0 :     _taskIDs.clear();
     566           0 : }
     567             : 
     568           9 : ViewEqualizer::Listener::Load ViewEqualizer::Listener::Load::NONE( 0, 0, 1 );
     569           9 : ViewEqualizer::Listener::Load::Load( const uint32_t frame_,
     570             :                                      const uint32_t missing_,
     571             :                                      const int64_t time_ )
     572             :         : frame( frame_ ), missing( missing_ ), nResources( missing_ )
     573           9 :         , time( time_ ) {}
     574             : 
     575           0 : bool ViewEqualizer::Listener::Load::operator == ( const Load& rhs ) const
     576             : {
     577           0 :     return ( frame == rhs.frame && missing == rhs.missing && time == rhs.time );
     578             : }
     579             : 
     580           0 : void ViewEqualizer::Listener::notifyLoadData( Channel* channel,
     581             :                                               const uint32_t frameNumber,
     582             :                                               const Statistics& statistics,
     583             :                                               const Viewport& /*region*/ )
     584             : {
     585           0 :     Load& load = _getLoad( frameNumber );
     586           0 :     if( load == Load::NONE )
     587           0 :         return;
     588             : 
     589           0 :     LBASSERT( _taskIDs.find( channel ) != _taskIDs.end( ));
     590           0 :     const uint32_t taskID = _taskIDs[ channel ];
     591             : 
     592             :     // gather relevant load data
     593           0 :     int64_t startTime = std::numeric_limits< int64_t >::max();
     594           0 :     int64_t endTime   = 0;
     595           0 :     bool  loadSet   = false;
     596           0 :     int64_t transmitTime = 0;
     597           0 :     for( size_t i = 0; i < statistics.size() && !loadSet; ++i )
     598             :     {
     599           0 :         const eq::Statistic& data = statistics[i];
     600           0 :         if( data.task != taskID ) // data from another compound
     601           0 :             continue;
     602             : 
     603           0 :         switch( data.type )
     604             :         {
     605             :         case eq::Statistic::CHANNEL_CLEAR:
     606             :         case eq::Statistic::CHANNEL_DRAW:
     607             :         case eq::Statistic::CHANNEL_READBACK:
     608           0 :             startTime = LB_MIN( startTime, data.startTime );
     609           0 :             endTime   = LB_MAX( endTime, data.endTime );
     610           0 :             break;
     611             : 
     612             :         case Statistic::CHANNEL_ASYNC_READBACK:
     613             :         case Statistic::CHANNEL_FRAME_TRANSMIT:
     614           0 :             transmitTime += data.startTime - data.endTime;
     615           0 :             break;
     616             :         case Statistic::CHANNEL_FRAME_WAIT_SENDTOKEN:
     617           0 :             transmitTime -= data.endTime - data.startTime;
     618           0 :             break;
     619             : 
     620             :             // assemble blocks on input frames, stop using subsequent data
     621             :         case eq::Statistic::CHANNEL_ASSEMBLE:
     622           0 :             loadSet = true;
     623           0 :             break;
     624             : 
     625             :         default:
     626           0 :             break;
     627             :         }
     628             :     }
     629             : 
     630           0 :     if( startTime == std::numeric_limits< int64_t >::max( ))
     631           0 :         return;
     632             : 
     633           0 :     LBASSERTINFO( load.missing > 0, load << " for " << channel->getName() <<
     634             :                                     " " << channel->getSerial( ));
     635             : 
     636           0 :     const int64_t time = LB_MAX(endTime - startTime, transmitTime );
     637           0 :     load.time += time;
     638           0 :     --load.missing;
     639             : 
     640           0 :     if( load.missing == 0 )
     641             :     {
     642           0 :         const float rTime = float( load.time ) / float( load.nResources );
     643           0 :         load.time = int64_t( rTime * sqrtf( float( load.nResources )));
     644             :     }
     645             : 
     646           0 :     LBLOG( LOG_LB1 ) << "Task " << taskID << ", added time " << time << " to "
     647           0 :                      << load << " from " << channel->getName() << " "
     648           0 :                      << channel->getSerial() << std::endl;
     649             : }
     650             : 
     651           0 : uint32_t ViewEqualizer::Listener::findYoungestLoad( const uint32_t frame ) const
     652             : {
     653             : 
     654           0 :     for( LoadDeque::const_iterator i = _loads.begin(); i != _loads.end(); ++i )
     655             :     {
     656           0 :         const Load& load = *i;
     657           0 :         if( load.missing == 0 && load.frame <= frame )
     658           0 :             return load.frame;
     659             :     }
     660           0 :     return 0;
     661             : }
     662             : 
     663             : const ViewEqualizer::Listener::Load&
     664           0 : ViewEqualizer::Listener::useLoad( const uint32_t frame )
     665             : {
     666           0 :     for( LoadDeque::iterator i = _loads.begin(); i != _loads.end(); ++i )
     667             :     {
     668           0 :         Load& load = *i;
     669           0 :         if( load.frame == frame )
     670             :         {
     671           0 :             LBASSERT( load.missing == 0 );
     672           0 :             if( load.time == 0 )
     673           0 :                 load.time = 1;
     674             : 
     675           0 :             ++i;
     676           0 :             _loads.erase( i, _loads.end( ));
     677           0 :             return load;
     678             :         }
     679             :     }
     680             : 
     681           0 :     return Load::NONE;
     682             : }
     683             : 
     684             : ViewEqualizer::Listener::Load&
     685           0 : ViewEqualizer::Listener::_getLoad( const uint32_t frame )
     686             : {
     687           0 :     for( LoadDeque::iterator i = _loads.begin(); i != _loads.end(); ++i )
     688             :     {
     689           0 :         const Load& load = *i;
     690           0 :         if( load.frame == frame )
     691           0 :             return *i;
     692             :     }
     693             : 
     694           0 :     return Load::NONE;
     695             : }
     696             : 
     697           0 : void ViewEqualizer::Listener::newLoad( const uint32_t frameNumber,
     698             :                                        const uint32_t nChannels )
     699             : {
     700           0 :     LBASSERT( nChannels > 0 );
     701           0 :     _loads.push_front( Load( frameNumber, nChannels, 0 ));
     702           0 : }
     703             : 
     704           8 : std::ostream& operator << ( std::ostream& os, const ViewEqualizer* equalizer )
     705             : {
     706           8 :     if( equalizer )
     707           8 :         os << "view_equalizer {}" << std::endl;
     708           8 :     return os;
     709             : }
     710             : 
     711           0 : std::ostream& operator << ( std::ostream& os,
     712             :                             const ViewEqualizer::Listener& listener )
     713             : {
     714           0 :     os << lunchbox::disableFlush << "Listener" << std::endl
     715           0 :        << lunchbox::indent;
     716           0 :     for( ViewEqualizer::Listener::LoadDeque::const_iterator i =
     717           0 :              listener._loads.begin(); i != listener._loads.end(); ++i )
     718             :     {
     719           0 :         os << *i << std::endl;
     720             :     }
     721           0 :     os << lunchbox::exdent << lunchbox::enableFlush;
     722           0 :     return os;
     723             : }
     724             : 
     725           0 : std::ostream& operator << ( std::ostream& os,
     726             :                             const ViewEqualizer::Listener::Load& load )
     727             : {
     728           0 :     os << "frame " << load.frame << " missing " << load.missing << " t "
     729           0 :        << load.time;
     730           0 :     return os;
     731             : }
     732             : 
     733             : }
     734          27 : }

Generated by: LCOV version 1.10