
2009/7/24 Frank Mori Hess <frank.hess@nist.gov>:
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