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 |
|