Skip to content
Aug 24 / Danushka

Boost signals (1.36.0) vs. sigc++ (2.0.18)

Recently my engine has needed an upgrade to its event system (observer/publisher). Currently, there is little overhead involved but this is achieved by using macro’s which inline function calls. This is neither maintainable nor extensible and has lead to problems while trying to develop a reliable shutdown sequence for the engine (e.g. when fatal exceptions are caught) – this is mainly due to the intense parallelism present in the architecture.

I found several implementations of the “signals & slots” design pattern, the stand-outs were boost::signals, sigc++-2.0 and a very lightweight implementation called sigslot-1-0-0.

Reading on the internet (boost mailing lists as well as Sneftel’s post on GDnet) lead me to believe that boost::signals had performance issues, however with the recent release of 1.36.0 I wasn’t sure about how valid these bits of information were, so I spent a few hours today developing a benchmark which netted the results inserted at the end of this post.

The signals_bench.cpp C++ source code is not as simple as it could be, but should be easy enough to follow. I chose to use templates/compile time code generation to keep runtime overhead low and also as a bit of practice, as my full-time job is uses Java.

So Boost seems to be faster when you have many signals and many slots for each signal. The 1000×1000 test returned 22 seconds for sigc++ and only 3 seconds for boost::signals. Don’t really know why, but it’s a bit out of place when you take note that boost signals basically gets its ass handed to it by sigc++ in all the other tests. the 5×100000 test b::s returns 1.5 seconds where sc++ returns 0.5 seconds.

The next thing to test is multi-threaded performance, neither library natively supports threading, however sigc++ has an addon called sigc++extras or sigcx, interestingly sigslots is already thread safe. I will have to manually wrap boost::signals so that will be interesting to do..

I will be including sigslots in the next round of testing… whenever that is. (I ran out of time today, might repost with those results if I have time this week)

Just on a side note, the two libraries syntaxes are so similar, you may be able to develop a hybrid wrapper which can switch libraries at runtime. Would be interesting to see how this would help if it were used in a “real-world™” scenario.

Results

description setup time run time signals slots
boost::signals 1.36.0 0.003000 2.988000 1000 1000
boost::signals 1.36.0 0.000000 0.000000 100 1
boost::signals 1.36.0 0.000000 0.003000 100 10
boost::signals 1.36.0 0.000000 0.029000 100 100
boost::signals 1.36.0 0.000000 0.001000 5 1
boost::signals 1.36.0 0.000000 0.000000 5 10
boost::signals 1.36.0 0.000000 0.001000 5 100
boost::signals 1.36.0 0.001000 0.015000 5 1000
boost::signals 1.36.0 0.001000 0.148000 5 10000
boost::signals 1.36.0 0.010000 1.487000 5 100000
boost::signals 1.36.0 0.000000 0.000000 4 1
boost::signals 1.36.0 0.000000 0.000000 4 10
boost::signals 1.36.0 0.000000 0.001000 4 100
boost::signals 1.36.0 0.001000 0.012000 4 1000
boost::signals 1.36.0 0.001000 0.119000 4 10000
boost::signals 1.36.0 0.011000 1.189000 4 100000
boost::signals 1.36.0 0.000000 0.000000 3 1
boost::signals 1.36.0 0.000000 0.000000 3 10
boost::signals 1.36.0 0.000000 0.001000 3 100
boost::signals 1.36.0 0.000000 0.008000 3 1000
boost::signals 1.36.0 0.001000 0.090000 3 10000
boost::signals 1.36.0 0.011000 0.895000 3 100000
boost::signals 1.36.0 0.000000 0.000000 2 1
boost::signals 1.36.0 0.000000 0.000000 2 10
boost::signals 1.36.0 0.000000 0.001000 2 100
boost::signals 1.36.0 0.000000 0.006000 2 1000
boost::signals 1.36.0 0.001000 0.059000 2 10000
boost::signals 1.36.0 0.011000 0.585000 2 100000
boost::signals 1.36.0 0.000000 0.000000 1 1
boost::signals 1.36.0 0.000000 0.000000 1 10
boost::signals 1.36.0 0.000000 0.001000 1 100
boost::signals 1.36.0 0.000000 0.003000 1 1000
boost::signals 1.36.0 0.001000 0.029000 1 10000
boost::signals 1.36.0 0.011000 0.291000 1 100000
sigc++ 2.0.18 0.000000 21.526000 1000 1000
sigc++ 2.0.18 0.000000 0.000000 100 1
sigc++ 2.0.18 0.000000 0.001000 100 10
sigc++ 2.0.18 0.000000 0.012000 100 100
sigc++ 2.0.18 0.000000 0.000000 5 1
sigc++ 2.0.18 0.000000 0.000000 5 10
sigc++ 2.0.18 0.000000 0.001000 5 100
sigc++ 2.0.18 0.000000 0.005000 5 1000
sigc++ 2.0.18 0.000000 0.046000 5 10000
sigc++ 2.0.18 0.000000 0.473000 5 100000
sigc++ 2.0.18 0.000000 0.000000 4 1
sigc++ 2.0.18 0.000000 0.000000 4 10
sigc++ 2.0.18 0.000000 0.000000 4 100
sigc++ 2.0.18 0.000000 0.004000 4 1000
sigc++ 2.0.18 0.001000 0.037000 4 10000
sigc++ 2.0.18 0.000000 0.378000 4 100000
sigc++ 2.0.18 0.000000 0.000000 3 1
sigc++ 2.0.18 0.000000 0.000000 3 10
sigc++ 2.0.18 0.000000 0.001000 3 100
sigc++ 2.0.18 0.000000 0.002000 3 1000
sigc++ 2.0.18 0.000000 0.029000 3 10000
sigc++ 2.0.18 0.001000 0.287000 3 100000
sigc++ 2.0.18 0.000000 0.000000 2 1
sigc++ 2.0.18 0.000000 0.000000 2 10
sigc++ 2.0.18 0.000000 0.000000 2 100
sigc++ 2.0.18 0.000000 0.002000 2 1000
sigc++ 2.0.18 0.000000 0.020000 2 10000
sigc++ 2.0.18 0.001000 0.196000 2 100000
sigc++ 2.0.18 0.000000 0.000000 1 1
sigc++ 2.0.18 0.000000 0.000000 1 10
sigc++ 2.0.18 0.000000 0.000000 1 100
sigc++ 2.0.18 0.000000 0.001000 1 1000
sigc++ 2.0.18 0.000000 0.010000 1 10000
sigc++ 2.0.18 0.001000 0.110000 1 100000

4 Comments

leave a comment
  1. Atif / Jun 19 2009

    Did you try running the test with the new boost::signals2 implementation? Its a rework of the original boost::signals to include thread safety.

  2. silvermace / Jun 21 2009

    Hi, no I haven’t yet, I should take a look at that. Thanks for the comment :)

  3. John / Aug 27 2009

    Did you ever get around to benchmarking sigslot?

  4. silvermace / Sep 9 2009

    Hi John, no I didn’t, unfortunately time hasn’t allowed me to get back to this test, but I think a few projects coming up will be using the signals-slots pattern so I will post if I end up evaluating sigslot.

Leave a Comment