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

Generated by: LCOV version 1.11