Boost logo

Boost :

Subject: Re: [boost] several messages
From: Marc Glisse (marc.glisse_at_[hidden])
Date: 2012-08-05 06:17:16


On Sun, 5 Aug 2012, John Maddock wrote:

> As noted in a recent post - the cost of wrapping a native type inside
> mp_number should be close to zero now *when expression templates are off*.
>
> When ET's are turned on, this will always IMO be slower, consider an operator
> returning an expression template - it's basically returning a pair of
> references (and larger objects still for more complex expressions), where as
> say a wrapped integer is actually returning a smaller cheaper to copy object
> in that case. So for a wrapped integer, returning the result by value will
> always win out, and that's before you even consider the cost of unpacking the
> expression template.

I believe you are a bit pessimistic. Compilers are not bad at inlining
functions and removing wrappers that do nothing, even for
expression-templates. And yes, returning a pair of references is doing
nothing if your function is inlined. Some analysis of what remains would
be interesting. What usually happens is that:
* expression template wrappers sometimes contain runtime checks (e.g. for
aliasing between variables), some of which can be impossible to determine
at compile-time;
* some compiler optimization opportunities that would have happened
early are now only exposed after a lot of inlining / simplification has
taken place, which may be too late for some compilers (but then it is not
too hard for compilers to make progress there, if it is pointed out to
them).

> I have an open question for you all: I was planning on working on cpp_int
> performance next, and trying to improve the computation geometry use cases.
> Obviously that pushes back a potential release. The alternative is to
> address all the issues relating to the front end first, and aim for an
> earlier first release. Which would folks prefer?

IMHO: front-end first, back-ends later.

On Sun, 5 Aug 2012, John Maddock wrote:

>> The problem is illustrated via something like
>>
>> a = move(a) + b;
>>
>> Of course, the above is better written as "a += b", but it's exemplary of
>> more elaborate assignments, e.g., "a = c * move(a) + b". Indeed, an even
>> simpler example is just "a = move(a)", given John's implementation of
>> operator+ above and ignoring the arithmetic (which is not relevant). And
>> the problem with "a = move(a)" in a generic context is that
>> T::operator=(T&& x) may freely assume that this != &x [1], mostly for
>> efficiency purposes (Dave, correct me if I'm wrong here).
>>
>> So, in other words, don't return an rvalue reference from a function which
>> is a reference to one of its arguments unless this is explicitly intended
>> and documented (e.g., move and forward).
>>
>> Note that changing the return type from Number&& to Number cancels the
>>> allocation gain when using a type like GMP that doesn't have an empty
>>> state.
>>>
>>
>> Huh, really? That's no good.
>
> Don't panic it's OK ;-)
>
> The current sandbox code, does have these rvalue ref operator overloads, does
> return by value for safety, and still manages to avoid the extra allocations
> - so for example in my horner test case, evaluating:
>
> Real result = (((((a[6] * x + a[5]) * x + a[4]) * x + a[3]) * x + a[2]) * x +
> a[1]) * x + a[0];
>
> Reuslts in just one allocation even when expression templates are turned off
> - the first operator overload called generates a temporary, which then gets
> moved and reused, eventually ending up in the result.

Uh?
This is indeed what happens, but for GMP types, unless you added in your
wrapper a special 0 state (which you then have to test in every
operation), every constructor has to allocate, including the move
constructor, since a moved-from object must still be in a valid state.

Did you add an empty state then?

-- 
Marc Glisse

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