Boost logo

Boost Users :

Subject: Re: [Boost-users] [Signals] Another performance discussion
From: Sajjan Kalle (sairony_at_[hidden])
Date: 2009-07-24 11:56:36


2009/7/24 Frank Mori Hess <frank.hess_at_[hidden]>:
> You should add a fragmented test using plain iteration over a std::list to
> your benchmark.  Also, you could try using a dummy_mutex for the signals2
> signals, like:
>
> namespace bs2 = boost::signals2;
> using bs2::keywords;
> bs2::signal_type<void (void), mutex_type<bs2::dummy_mutex> >::type
>  boostSignal2Fragmented, boostSignal2Unfragmented;
>

With dummy_mutex the unfragmented version of signals2 is about twice
as fast as the unfragmented signals version, finnishing at 0.514. Is
there any advantage of signals over signals2? Perhaps it should be
deprecated. Here's the new version, slightly changed in a few areas.

#include <iostream>
#include "boost/signals.hpp"
#include <vector>
#include "boost/function.hpp"
#include "boost/timer.hpp"
#include "boost/signals2/signal.hpp"
#include "boost/signals2/dummy_mutex.hpp"
#include "boost/signals2/signal_type.hpp"
#include <cstdlib>
#include <algorithm>

void foo( )
{
}

int main()
{
        std::vector< boost::function< void ( void ) > > manualSignal;
        typedef std::list< boost::function< void ( void ) > >::iterator
SigListIterator;
        std::list< boost::function< void ( void ) > >
manualSignalListUnfragmented, manualSignalListFragmented;
        boost::signal< void ( void ) > boostSignalFragmented, boostSignalUnfragmented;
        namespace bs2 = boost::signals2;
        bs2::signal_type<void (void),
bs2::keywords::mutex_type<bs2::dummy_mutex> >::type
                boostSignal2Fragmented, boostSignal2Unfragmented;
        typedef std::vector< boost::signals::connection > ConnectionVector;
        typedef std::vector< boost::signals2::connection > ConnectionVector2;
        ConnectionVector connections;
        ConnectionVector2 connections2;
        for( unsigned int i = 0; i < 10000; ++i )
                manualSignalListUnfragmented.push_back( &foo );
        for( unsigned int i = 0; i < 10000; ++i )
                manualSignal.push_back( &foo );
        for( unsigned int i = 0; i < 10000; ++i )
                boostSignal2Unfragmented.connect( &foo );
        for( unsigned int i = 0; i < 10000; ++i )
                boostSignalUnfragmented.connect( &foo );
        
        for( unsigned int i = 0; i < 100000; ++i )
        {
                manualSignalListFragmented.push_back( &foo );
                connections.push_back( boostSignalFragmented.connect( &foo ) );
                connections2.push_back( boostSignal2Fragmented.connect( &foo ) );
        }
        for( unsigned int i = 0; i < 90000; ++i )
        {
                {
                        SigListIterator index = manualSignalListFragmented.begin();
                        std::advance( index, rand() % manualSignalListFragmented.size() );
                        manualSignalListFragmented.erase( index );
                }
                {
                        ConnectionVector::iterator index = connections.begin() + rand() %
connections.size();
                        (*index).disconnect();
                        *index = *connections.rbegin();
                        connections.erase( connections.begin() + connections.size() - 1 );
                }
                {
                        ConnectionVector2::iterator index = connections2.begin() + rand() %
connections2.size();
                        (*index).disconnect();
                        *index = *connections2.rbegin();
                        connections2.erase( connections2.begin() + connections2.size() - 1 );
                }
        }
        {
                boost::timer tm;
                for( unsigned int i = 0; i < 1000; ++i )
                {
                        for( unsigned int j = 0; j < 10000; ++j )
                                manualSignal[ i ]( );
                }
                double elapsed = tm.elapsed();
                std::cout << "vector variant: " << elapsed << std::endl;
        }
        {
                boost::timer tm;
                for( unsigned int i = 0; i < 1000; ++i )
                {
                        boostSignalUnfragmented( );
                }
                double elapsed = tm.elapsed();
                std::cout << "boost::signal unfragmented variant: " << elapsed << std::endl;
        }
        {
                boost::timer tm;
                for( unsigned int i = 0; i < 1000; ++i )
                {
                        boostSignalFragmented( );
                }
                double elapsed = tm.elapsed();
                std::cout << "boost::signal fragmented variant: " << elapsed << std::endl;
        }
        {
                boost::timer tm;
                for( unsigned int i = 0; i < 1000; ++i )
                {
                        boostSignal2Unfragmented( );
                }
                double elapsed = tm.elapsed();
                std::cout << "boost::signal2 unfragmented variant: " << elapsed << std::endl;
        }
        {
                boost::timer tm;
                for( unsigned int i = 0; i < 1000; ++i )
                {
                        boostSignal2Fragmented( );
                }
                double elapsed = tm.elapsed();
                std::cout << "boost::signal2 Fragmented variant: " << elapsed << std::endl;
        }
        {
                boost::timer tm;
                for( unsigned int i = 0; i < 1000; ++i )
                {
                        for( SigListIterator itrCur = manualSignalListUnfragmented.begin(),
itrEnd = manualSignalListUnfragmented.end(); itrCur != itrEnd;
++itrCur )
                                (*itrCur)( );
                }
                double elapsed = tm.elapsed();
                std::cout << "list unfragmented variant: " << elapsed << std::endl;
        }
        {
                boost::timer tm;
                for( unsigned int i = 0; i < 1000; ++i )
                {
                        for( SigListIterator itrCur = manualSignalListFragmented.begin(),
itrEnd = manualSignalListFragmented.end(); itrCur != itrEnd; ++itrCur
)
                                (*itrCur)( );
                }
                double elapsed = tm.elapsed();
                std::cout << "list fragmented variant: " << elapsed << std::endl;
        }
}

I guess the fragmented signals2 version isn't all that interesting
anymore, but I left it in there anyway since it doesn't take much
time. The running time is now considerably higher due to the slowness
of random access on a list. These are the results this code nets me:

vector 0.038
unfrag signal 0.936
frag signal 1.745
unfrag signal2 0.457
frag signal2 3.512
unfrag list 0.049
frag list 0.126


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net