Boost logo

Boost :

From: Vladimir Prus (ghost_at_[hidden])
Date: 2005-12-22 10:39:48


Douglas Gregor wrote:

>> Ok, let me try a comparison against vector of function pointers and
>> vectors
>> of boost::function. Test case attached. And I have another test
>> cast, also
>> attached, which tests signals performance in Qt.
>>
>> Results:
>> function pointer 0.1 sec
>> Boost::function: 0.31 sec
>> Boost::signals 9.5 sec
>> Qt 1.3 sec
>>
>> Boost.Signals is 30 times slower then Boost.function and 95 times
>> slower
>> than function
>
> So it was 50 times slower than a single Boost.function, 30 times
> slower than a single Boost.function in a vector.

Precisely. The performance difference between Boost.function and
vector<Boost.Function> is a bit strange itself, as vector iteration should
become a simple loop, but it's a tiny compared to boost.signals.

>>> 2) target function objects can modify the iteration sequence during
>>> iteration. This results in additional iteration overhead that doesn't
>>> show up in the simple models, e.g., because one can add or remove
>>> slots
>>> while iterating through the list.
>>
>> What is the use case for that?
>
> It's especially good for one-shot slots: connect the slot, then once
> it fires it disconnects itself.

If it disconnects *itself*, then it might be possible to defer removing
such slots from whatever list they are in, until the iteration is done.

> It also happens when slots cause one
> of the objects connected to them to essentially "delete this", as
> would happen if your slot involved destroying a window within a GUI.
> This happens surprisingly often.

Again, this means that a slot disconnects *itself*. It does not change the
traversal for other slots. So this might be deferred.

>> And BTW, what is the use case for temporary
>> blocking specific connection?
>
> It was a persistent user request followed by a patch from a user. I
> don't recall the use cases, but I expect it has something to do with
> temporarily disabling calls into a component while that component is
> reinitializing itself.

Hmm, isn't this better handled on the component side, by adding

   if (reinializing)

to all handlers? I don't see why temporary disabling all connections (which
you need to store somehow) is better then adding "ifs". Or, it's possible
to use an adapter class -- a pair of boost::function and bool that has
operator() and will call the contained boost::function is bool member is
true. That would allow to solve the original problem outside boost.signals,
and not impose the overhead on everyone.

>>> I'm not saying that it isn't useful to compare the performance of
>>> Signals against simpler models, but we need to compare apples to
>>> apples
>>> if the comparison is going to help us improve.
>>
>> If by "apples to apples" you mean comparison to other signal
>> implementation,
>> then:
>> 1. See comparison with Qt above
>> 2. I don't think it's right anyway. Boost::signals has extra features
>> compares to Boost::function and it's fair to estimate the price those
>> features have compared to Boost::function .
>
> Sure, but we have to know what features we're measuring. There's no
> signal implementation that consists of a single function pointer, so
> while it does provide a lower bound on the call time for a signal,
> that bound doesn't tell us anything. vector<function<> > is a
> reasonable baseline: the we add features such as connect/disconnect
> stability during invocation, slot blocking/unblocking, and named
> slots and see where that gets us. My guess? The combination of named
> slots and my attempts to avoid code bloat are killing signals
> invocation performance.

BTW, what are those named slots? I've looked into the docs several times but
still did not figired that out.

>> Still, what do you think about some simplified boost::signal (maybe
>> a base
>> class, or a #ifdefed) that will have better performance?
>
> For I long time I've wanted to have a signal that doesn't permit
> named slots, so that we can replace the horrendous map<name,
> list<slot> > data structure in named_slot_map into a simple
> list<slot>. It even fits into the interface well: we would just add a
> partial specialization of signal<> like the following that uses the
> simple, faster list<slot>-type interface.
>
> template<typename Signature, typename Combiner, typename
> GroupCompare, typename SlotFunction>
> class signal<Signature, Combiner, void, GroupCompare,
> SlotFunction>;

That would be great.

- Volodya


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk