LCOV - code coverage report
Current view: top level - eq/server/equalizers - framerateEqualizer.cpp (source / functions) Hit Total Coverage
Test: lcov2.info Lines: 20 129 15.5 %
Date: 2014-06-18 Functions: 8 20 40.0 %

          Line data    Source code
       1             : 
       2             : /* Copyright (c) 2008-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 "framerateEqualizer.h"
      19             : 
      20             : #include "../compound.h"
      21             : #include "../compoundVisitor.h"
      22             : #include "../config.h"
      23             : #include "../log.h"
      24             : 
      25             : #include <eq/client/statistic.h>
      26             : #include <lunchbox/debug.h>
      27             : 
      28             : #define USE_AVERAGE
      29             : #define VSYNC_CAP 60.f
      30             : #define SLOWDOWN  1.05f
      31             : 
      32             : namespace eq
      33             : {
      34             : namespace server
      35             : {
      36             : 
      37             : namespace
      38             : {
      39           0 : class LoadSubscriber : public CompoundVisitor
      40             : {
      41             : public:
      42           0 :     LoadSubscriber( ChannelListener* listener ) : _listener( listener ) {}
      43             : 
      44           0 :     virtual VisitorResult visit( Compound* compound )
      45             :         {
      46           0 :             Channel*  channel = compound->getChannel();
      47           0 :             LBASSERT( channel );
      48           0 :             channel->addListener( _listener );
      49             : 
      50           0 :             return TRAVERSE_CONTINUE;
      51             :         }
      52             : 
      53             : private:
      54             :     ChannelListener* const _listener;
      55             : };
      56             : 
      57           0 : class LoadUnsubscriber : public CompoundVisitor
      58             : {
      59             : public:
      60           0 :     LoadUnsubscriber( ChannelListener* listener ) : _listener( listener ) {}
      61             : 
      62           0 :     virtual VisitorResult visit( Compound* compound )
      63             :         {
      64           0 :             Channel*  channel = compound->getChannel();
      65           0 :             LBASSERT( channel );
      66           0 :             channel->removeListener( _listener );
      67             : 
      68           0 :             return TRAVERSE_CONTINUE;
      69             :         }
      70             : 
      71             : private:
      72             :     ChannelListener* const _listener;
      73             : };
      74             : 
      75             : }
      76             : 
      77             : // The smooth load balancer adapts the framerate of the compound to be the
      78             : // average frame rate of all children, taking the DPlex period into account.
      79             : 
      80          14 : FramerateEqualizer::FramerateEqualizer()
      81          14 :         : _nSamples( 0 )
      82             : {
      83          14 :     LBINFO << "New FramerateEqualizer @" << (void*)this << std::endl;
      84          14 : }
      85             : 
      86           0 : FramerateEqualizer::FramerateEqualizer( const FramerateEqualizer& from )
      87             :         : Equalizer( from )
      88           0 :         , _nSamples( 0 )
      89             : {
      90           0 : }
      91             : 
      92          42 : FramerateEqualizer::~FramerateEqualizer()
      93             : {
      94          14 :     attach( 0 );
      95          28 : }
      96             : 
      97          42 : void FramerateEqualizer::attach( Compound* compound )
      98             : {
      99          42 :     _exit();
     100          42 :     Equalizer::attach( compound );
     101          42 : }
     102             : 
     103             : 
     104           0 : void FramerateEqualizer::_init()
     105             : {
     106           0 :     const Compound* compound = getCompound();
     107             : 
     108           0 :     if( _nSamples > 0 || !compound )
     109           0 :         return;
     110             : 
     111           0 :     _nSamples = 1;
     112             : 
     113             :     // Subscribe to child channel load events
     114           0 :     const Compounds& children = compound->getChildren();
     115             : 
     116           0 :     LBASSERT( _loadListeners.empty( ));
     117           0 :     _loadListeners.resize( children.size( ));
     118             : 
     119           0 :     for( size_t i = 0; i < children.size(); ++i )
     120             :     {
     121           0 :         Compound*      child        = children[i];
     122           0 :         const uint32_t period       = child->getInheritPeriod();
     123           0 :         LoadListener&  loadListener = _loadListeners[i];
     124             : 
     125           0 :         loadListener.parent = this;
     126           0 :         loadListener.period = period;
     127             : 
     128           0 :         LoadSubscriber subscriber( &loadListener );
     129           0 :         child->accept( subscriber );
     130             : 
     131           0 :         _nSamples = LB_MAX( _nSamples, period );
     132           0 :     }
     133             : 
     134           0 :     _nSamples = LB_MIN( _nSamples, 100 );
     135             : }
     136             : 
     137          42 : void FramerateEqualizer::_exit()
     138             : {
     139          42 :     const Compound* compound = getCompound();
     140          42 :     if( !compound || _nSamples == 0 )
     141          84 :         return;
     142             : 
     143           0 :     const Compounds& children = compound->getChildren();
     144             : 
     145           0 :     LBASSERT( _loadListeners.size() == children.size( ));
     146           0 :     for( size_t i = 0; i < children.size(); ++i )
     147             :     {
     148           0 :         Compound*      child        = children[i];
     149           0 :         LoadListener&  loadListener = _loadListeners[i];
     150             : 
     151           0 :         LoadUnsubscriber unsubscriber( &loadListener );
     152           0 :         child->accept( unsubscriber );
     153           0 :     }
     154             : 
     155           0 :     _loadListeners.clear();
     156           0 :     _times.clear();
     157           0 :     _nSamples = 0;
     158             : }
     159             : 
     160             : 
     161           0 : void FramerateEqualizer::notifyUpdatePre( Compound* compound,
     162             :                                           const uint32_t frameNumber )
     163             : {
     164           0 :     _init();
     165             : 
     166             :     // find starting point of contiguous block
     167           0 :     const ssize_t size = ssize_t( _times.size( ));
     168           0 :     ssize_t       from = 0;
     169           0 :     if( size > 0 )
     170             :     {
     171           0 :         for( ssize_t i = size-1; i >= 0; --i )
     172             :         {
     173           0 :             if( _times[i].second == 0.f )
     174             :             {
     175           0 :                 from = i;
     176           0 :                 break;
     177             :             }
     178             :         }
     179             :     }
     180             : 
     181             :     // find max / avg time in block
     182           0 :     size_t nSamples = 0;
     183             : #ifdef USE_AVERAGE
     184           0 :     float sumTime = 0.f;
     185             : #else
     186             :     float maxTime  = 0.f;
     187             : #endif
     188             : 
     189           0 :     LBLOG( LOG_LB2 ) << "Searching " << from+1 << ".." << size << std::endl;
     190           0 :     for( ++from; from < size && nSamples < _nSamples; ++from )
     191             :     {
     192           0 :         const FrameTime& time = _times[from];
     193           0 :         LBASSERT( time.first > 0 );
     194           0 :         LBASSERT( time.second != 0.f );
     195             : 
     196           0 :         ++nSamples;
     197             : #ifdef USE_AVERAGE
     198           0 :         sumTime += time.second;
     199             : #else
     200             :         maxTime = LB_MAX( maxTime, time.second );
     201             : #endif
     202           0 :         LBLOG( LOG_LB2 ) << "Using " << time.first << ", " << time.second
     203           0 :                          << "ms" << std::endl;
     204             :     }
     205             : 
     206           0 :     if( nSamples == _nSamples )       // If we have a full set
     207           0 :         while( from < ssize_t( _times.size( )))
     208           0 :             _times.pop_back();            //  delete all older samples
     209             :     // always execute code above to not leak memory
     210             : 
     211           0 :     if( isFrozen() || !compound->isActive() || !isActive( ))
     212             :     {
     213           0 :         compound->setMaxFPS( std::numeric_limits< float >::max( ));
     214           0 :         return;
     215             :     }
     216             : 
     217           0 :     if( nSamples > 0 )
     218             :     {
     219             :         //TODO: totalTime *= 1.f - damping;
     220             : #ifdef USE_AVERAGE
     221           0 :         const float time = (sumTime / nSamples) * SLOWDOWN;
     222             : #else
     223             :         const float time = maxTime * SLOWDOWN;
     224             : #endif
     225             : 
     226           0 :         const float fps = 1000.f / time;
     227             : #ifdef VSYNC_CAP
     228           0 :         if( fps > VSYNC_CAP )
     229           0 :             compound->setMaxFPS( std::numeric_limits< float >::max( ));
     230             :         else
     231             : #endif
     232           0 :             compound->setMaxFPS( fps );
     233             : 
     234           0 :         LBLOG( LOG_LB2 ) << fps << " Hz from " << nSamples << "/"
     235           0 :                          << _times.size() << " samples, " << time << "ms"
     236           0 :                          << std::endl;
     237             :     }
     238             : 
     239           0 :     if( frameNumber > 0 )
     240           0 :         _times.push_front( FrameTime( frameNumber, 0.f ));
     241           0 :     LBASSERT( _times.size() < 10 );
     242             : }
     243             : 
     244           0 : void FramerateEqualizer::LoadListener::notifyLoadData(
     245             :     Channel* channel, const uint32_t frameNumber, const Statistics& statistics,
     246             :     const Viewport& /*region*/  )
     247             : {
     248             :     // gather required load data
     249           0 :     int64_t startTime = std::numeric_limits< int64_t >::max();
     250           0 :     int64_t endTime   = 0;
     251           0 :     for( size_t i = 0; i < statistics.size(); ++i )
     252             :     {
     253           0 :         const eq::Statistic& data = statistics[i];
     254           0 :         switch( data.type )
     255             :         {
     256             :             case eq::Statistic::CHANNEL_CLEAR:
     257             :             case eq::Statistic::CHANNEL_DRAW:
     258             :             case eq::Statistic::CHANNEL_ASSEMBLE:
     259             :             case eq::Statistic::CHANNEL_READBACK:
     260           0 :                 startTime = LB_MIN( startTime, data.startTime );
     261           0 :                 endTime   = LB_MAX( endTime, data.endTime );
     262           0 :                 break;
     263             : 
     264             :             default:
     265           0 :                 break;
     266             :         }
     267             :     }
     268             : 
     269           0 :     if( startTime == std::numeric_limits< int64_t >::max( ))
     270           0 :         return;
     271             : 
     272           0 :     if( startTime == endTime ) // very fast draws might report 0 times
     273           0 :         ++endTime;
     274             : 
     275           0 :     for( std::deque< FrameTime >::iterator i = parent->_times.begin();
     276           0 :          i != parent->_times.end(); ++i )
     277             :     {
     278           0 :         FrameTime& frameTime = *i;
     279           0 :         if( frameTime.first != frameNumber )
     280           0 :             continue;
     281             : 
     282           0 :         const float time = static_cast< float >( endTime - startTime ) / period;
     283           0 :         frameTime.second = LB_MAX( frameTime.second, time );
     284           0 :         LBLOG( LOG_LB2 ) << "Frame " << frameNumber << " channel "
     285           0 :                         << channel->getName() << " time " << time
     286           0 :                         << " period " << period << std::endl;
     287             :     }
     288             : }
     289             : 
     290           7 : std::ostream& operator << ( std::ostream& os, const FramerateEqualizer* lb )
     291             : {
     292           7 :     if( lb )
     293           7 :         os << "framerate_equalizer {}" << std::endl;
     294           7 :     return os;
     295             : }
     296             : 
     297             : }
     298          27 : }

Generated by: LCOV version 1.10