Comparison: Signal and slot system performance
From DaevsGUI
-- Updated on 18 July 2010
After reading and running the comparison in this thread: http://www.gamedev.net/community/forums/topic.asp?topic_id=456646 I retrieved the following results (GCC 4.4.1, Win7 32bit):
Trails: 1000000 Computing using regular function...653067456. Computation time: 45ms. Computing using Events.............653067456. Computation time: 136ms. Computing using Boost Signals......653067456. Computation time: 800ms. Computing using SigC++.............653067456. Computation time: 402ms. Computing using DaevsSignals.......653067456. Computation time: 138ms. Trails: 10000000 Computing using regular function...1332236160. Computation time: 445ms. Computing using Events.............1332236160. Computation time: 1360ms. Computing using Boost Signals......1332236160. Computation time: 7981ms. Computing using SigC++.............1332236160. Computation time: 3993ms. Computing using DaevsSignals.......1332236160. Computation time: 1374ms.
This shows that my implementation typically is about as fast as 'Events' by Sneftel, which uses FastDelegates from Don Clugston. One thing to note, however, is that my implementation works only with a pointer as parameter (in this particular set up; it can support up to 8 parameters) and that this parameter must be set at connection time (it saves the parameter). This allows signals to have other signals as slots (if it were not for saving the parameters, how else would the initial signal know what parameters to pass to the second signal). Using a parameter set at connection time is safer and less complex. Note that my signal and slot system can also have up to about 8 parameters.
I'm quite satisfied that a naive solution which I wrote is as fast as FastDelegates for my particular development machine.
#include "event.h" #include <iostream> #include <string> #include <boost/signal.hpp> #include <boost/signals/connection.hpp> #include <boost/bind.hpp> #include "sigc++/sigc++.h" #include <Windows.h> #include <DaevsCommon/signal.hpp> #include <DaevsCommon/slots.hpp> int sum = 0; void AddToSum(int n) { sum += n; } class EventHandler : public events::AutoTracked { public: void AddToSum(int n) { sum += n; } events::ConnectionSet connectionSet; }; class SignalHandler { public: void AddToSum(int n) { sum += n; } }; class SigCHandler : public sigc::trackable { public: void AddToSum(int n) { sum += n; } }; class DaevsSignal { public: DaevsSignal() : slots() { } DaevsSignal(const DaevsSignal &instance) : slots() { } void AddToSum(int *n) { sum += *n; } DaevsCommon::Slots slots; }; static int NUM_TRIALS = 1000000; static const int NUM_HANDLERS = 10; int main() { for (int j = 0; j < 2; j++) { if (j == 1) { NUM_TRIALS = 10000000; } std::cout << "\nTrails: " << NUM_TRIALS << std::endl; sum = 0; { std::cout << "Computing using regular function..."; DWORD startTime = timeGetTime(); for (int j = 0; j < NUM_HANDLERS; j++) { for (int i = 0; i < NUM_TRIALS; i++) { AddToSum(i); } } DWORD endTime = timeGetTime(); std::cout << sum << ". Computation time: " << endTime - startTime << "ms." << std::endl; } sum = 0; { std::cout << "Computing using Events..."; events::Event<int> e; std::vector<EventHandler> handlers(NUM_HANDLERS); for(std::vector<EventHandler>::iterator ih = handlers.begin(), eh = handlers.end(); ih != eh; ++ih) { e.AutoRegister(*ih, &EventHandler::AddToSum); } DWORD startTime = timeGetTime(); for (int i = 0; i < NUM_TRIALS; i++) { e.Invoke(i); } DWORD endTime = timeGetTime(); std::cout << sum << ". Computation time: " << endTime - startTime << "ms." << std::endl; } sum = 0; { std::cout << "Computing using Boost Signals..."; boost::signal<void(int)> s; std::vector<SignalHandler> handlers(NUM_HANDLERS); for (std::vector<SignalHandler>::iterator ih = handlers.begin(), eh = handlers.end(); ih != eh; ++ih) { s.connect(boost::bind(&SignalHandler::AddToSum, &*ih, _1)); } DWORD startTime = timeGetTime(); for (int i = 0; i < NUM_TRIALS; i++) { s(i); } DWORD endTime = timeGetTime(); std::cout << sum << ". Computation time: " << endTime - startTime << "ms." << std::endl; } sum = 0; { std::cout << "Computing using SigC++..."; sigc::signal<void, int> s; std::vector<SigCHandler> handlers(NUM_HANDLERS); for (std::vector<SigCHandler>::iterator ih = handlers.begin(), eh = handlers.end(); ih != eh; ++ih) { s.connect(sigc::ptr_fun(&AddToSum)); } DWORD startTime = timeGetTime(); for (int i = 0; i < NUM_TRIALS; i++) { s.emit(i); } DWORD endTime = timeGetTime(); std::cout << sum << ". Computation time: " << endTime - startTime << "ms." << std::endl; } sum = 0; { std::cout << "Computing using DaevsSignals..."; int i; DaevsCommon::Signal s; std::vector<DaevsSignal> handlers(NUM_HANDLERS); for (std::vector<DaevsSignal>::iterator ih = handlers.begin(), eh = handlers.end(); ih != eh; ++ih) { s.connect(&(*ih), &DaevsSignal::AddToSum, &i); } DWORD startTime = timeGetTime(); for (i = 0; i < NUM_TRIALS; i++) { s.emit(); } DWORD endTime = timeGetTime(); std::cout << sum << ". Computation time: " << endTime - startTime << "ms." << std::endl; } } }
