C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

The Return Value Optimisation

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Guy Davidson
Guest





PostPosted: Fri Jul 08, 2005 12:36 am    Post subject: The Return Value Optimisation Reply with quote



Is the Return Value Optimisation available to non-inlined functions?

My code shop is very keen to avoid passing by value. Rather than something
like this:

big_class foo(int p1, int p2)
{
return big_class(p1, p2);
}

void bar()
{
int p1 = 0;
int p2 = 1;
big_class bc(foo(p1, p2));
}

they'll do this:

void foo(int p1, int p2, big_class& bc_in)
{
bc_in.assign(p1, p2); /* like an assignment operator */
}

void bar()
{
int p1 = 0;
int p2 = 1;
big_class bc;
foo(p1,p2,bc);
}

In terms of constructor/destructor/copy constructor calls (assuming a
trivial default constructor) is it the case that the first form of foo will
only be more efficient if it is available for inlining? I'm assuming this
is the case, but More Effective C++ item 20 doesn't EXPLICITLY say that's
the case. I'm probably clutching at straws here, and I can't think how a
compiler might manage it (I suppose a linker might) but I wanted to ask the
community just to be sure.

Thanks for your help
J Guy Davidson



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
David Abrahams
Guest





PostPosted: Fri Jul 08, 2005 10:21 am    Post subject: Re: The Return Value Optimisation Reply with quote



"Guy Davidson" <guy.davidson (AT) hatcat (DOT) com> writes:

Quote:
Is the Return Value Optimisation available to non-inlined functions?

Yes, in principle. In practice whether RVO will be used depends on
your compiler.

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Greg
Guest





PostPosted: Fri Jul 08, 2005 10:30 am    Post subject: Re: The Return Value Optimisation Reply with quote




Guy Davidson wrote:
Quote:
Is the Return Value Optimisation available to non-inlined functions?

My code shop is very keen to avoid passing by value. Rather than something
like this:

big_class foo(int p1, int p2)
{
return big_class(p1, p2);
}

void bar()
{
int p1 = 0;
int p2 = 1;
big_class bc(foo(p1, p2));
}

they'll do this:

void foo(int p1, int p2, big_class& bc_in)
{
bc_in.assign(p1, p2); /* like an assignment operator */
}

void bar()
{
int p1 = 0;
int p2 = 1;
big_class bc;
foo(p1,p2,bc);
}

In terms of constructor/destructor/copy constructor calls (assuming a
trivial default constructor) is it the case that the first form of foo will
only be more efficient if it is available for inlining? I'm assuming this
is the case, but More Effective C++ item 20 doesn't EXPLICITLY say that's
the case. I'm probably clutching at straws here, and I can't think how a
compiler might manage it (I suppose a linker might) but I wanted to ask the
community just to be sure.

Thanks for your help
J Guy Davidson


The Named Return Value Optimization does not rely on function inlining
(it would not be much of optimization if it did). But it does require
that the function always return the same object and that the object
returned be named.

Since the first function foo in the example above returns an anonymous
big_class object, it fails to meet the latter requirement, and would
not be a candidate for NRVO.

A simple change quickly remedies the situation:

big_class foo(int p1, int p2)
{
big_class functionResult(p1, p2);

return functionResult;
}

With its return value now named, the NRVO can be applied, meaning that
a call to foo would effectively construct a big_class in place at the
call site.

Note also that the NRVO can be applied through a series of nested
function calls - were foo to call another function to obtain
functionResult and the function called had also been NRVO'd, then the
object returned by the innermost function would effectively be
constructed at the calling site two (or more) levels higher in the
calling chain.

Greg


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Martin Bonner
Guest





PostPosted: Fri Jul 08, 2005 10:32 am    Post subject: Re: The Return Value Optimisation Reply with quote

Guy Davidson wrote:
Quote:
Is the Return Value Optimisation available to non-inlined functions?
Yes.

My code shop is very keen to avoid passing by value. Rather than something
like this:

big_class foo1(int p1, int p2)
{
return big_class(p1, p2);
}

void bar1()
{
big_class bc(foo1(1,0));
}

they'll do this:

void foo2(int p1, int p2, big_class& bc_in)
{
bc_in.assign(p1, p2); /* like an assignment operator */
}

void bar2()
{
big_class bc;
foo(1,0,bc);
}

In terms of constructor/destructor/copy constructor calls (assuming a
trivial default constructor) is it the case that the first form of foo will
only be more efficient if it is available for inlining?

No.

A typical implementation of bar1 will look something like:

void bar1()
{
unsigned char bc[sizeof(big_class)];
foo1( &bc[0], 1, 0 );
// bc is now magically of type big_class.
}

Withour rvo, foo1 looks like:
void foo1(void *retVal, int p1, int p2)
{
big_class temp(p1,p2); // Construct temporary
new(retVal) big_class(temp); // Copy construct return value
// from temp using placement new.
// destruct temp.
}

With rvo, foo1 looks like:

void foo1(void *retVal, int p1, int p2)
{
new(retVal) big_class(p1,p2); // Construct return value in-situ
// with placement new.
}

Note that the implementation of bar1 has not had to change at all. The
only difference is that there is an additional call to a copy
constructor and destructor within foo1.

Notes:
a) Determining whether your compiler applies the rvo is tricky. The
best way is probably to look at the generated assembler.
b) "Premature optimization is the root of all evil". Is there any
evidence that copying these classes is actually causing a performance
problem?
c) This isn't really "pass by value", it is "return by value" </pedant>


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Fri Jul 08, 2005 11:12 am    Post subject: Re: The Return Value Optimisation Reply with quote

Guy Davidson wrote:
Quote:
Is the Return Value Optimisation available to non-inlined functions?

Inlining has absolutely no effect on program semantics.
(According to the standard, at least.)

Quote:
My code shop is very keen to avoid passing by value. Rather
than something like this:

big_class foo(int p1, int p2)
{
return big_class(p1, p2);
}

void bar()
{
int p1 = 0;
int p2 = 1;
big_class bc(foo(p1, p2));
}

they'll do this:

void foo(int p1, int p2, big_class& bc_in)
{
bc_in.assign(p1, p2); /* like an assignment operator */
}

void bar()
{
int p1 = 0;
int p2 = 1;
big_class bc;
foo(p1,p2,bc);
}

In terms of constructor/destructor/copy constructor calls
(assuming a trivial default constructor) is it the case that
the first form of foo will only be more efficient if it is
available for inlining?

Efficiency always depends on the compiler. If the class has any
dynamic memory or such, it's likely that with some compilers,
the first form is more efficient, regardless of inline or not.
More generally, however: write the code cleanly. If it's fast
enough, it's fast enough. If not, profiling will show you where
to optimize. For the particular compiler you are using.

Quote:
I'm assuming this is the case, but More Effective C++ item 20
doesn't EXPLICITLY say that's the case. I'm probably
clutching at straws here, and I can't think how a compiler
might manage it (I suppose a linker might) but I wanted to ask
the community just to be sure.

The usual trick is merging two variables. The classical
solution for returning a class type is for the compiler to
allocate memory for it at the call site, and pass the address of
this memory as a hidden parameter to the function. The object
itself is constructed in the function. Once the function
returns, the compiler generates the code to do whatever it has
to do with the object, and destructs it. If the compiler
implements NRO, in your first example, it will not allocate
memory for the temporary return object, but will pass the
address of bc as the hidden parameter. The function then
constructs its return value directly in the target object, and
the copy and the delete of the temporary object is elided.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Guy Davidson
Guest





PostPosted: Sat Jul 09, 2005 1:44 am    Post subject: Re: The Return Value Optimisation Reply with quote

Thank you for your responses. In summary you appear to be saying:

DA:
Depends on the compiler, but availability for inlining DOES NOT affect
availability for RVO

Greg:
I have the name wrong - the optimisation is in fact called the Named Return
Value Optimisation. The object must be named to facilitate this
optimisation. Bonus - it nests!

MB (with thanks for enumerating my example functions):
In particular, the compiler will secretly pass an extra parameter describing
where to create the returned value. This removes the extra
copy-construct-from-temporary/destroy-temporary calls. However, check to
see if the compiler implements this mode of behaviour, beware premature
optimisation, and get the name right ;-)

JK:
Backing up MB's viewpoints.

A couple of points to clarify:
1. Greg - I'm looking at the Effective C++ CD and, in item M20, there is a
footnote about both named and unnamed objects being eligible for being
optimised away. Has this decision (made in July 1996) been revoked?
2. MB, JK - Your point about premature optimisation is well made, and I
agree with them in principle. However, my code shop is in a rather unusual
situation. We write PC games (just finishing the add-on for Rome:Total War
to be precise) and, in this domain, it always needs to be As Fast As
Possible. We can't operate by saying "I know it's not fast enough at the
moment, but when we optimise, you will see 10,000 men on screen, not 2,000.
Honest." The cost/benefit of optimisation is in front of us for every line
of code. I welcome any remedies to this situation anyone has to offer.
3. Explicitly, this problem arose with the Intel compiler (I think we're
using version Cool - passing and returning by value was occasionally resulting
in memory leaks with some types, that weren't appearing with the Microsoft
compiler (VC6) (yes, 6, the code base is approaching its 5th birthday). It
appears to be very difficult to reproduce it in isolation - does anyone else
have experience of this kind of problem?

I shall check some assembly on VC6, VC7.1 and ICC8 and report back my
findings (if anyone's interested!)

Cheers,
JGD



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Walter
Guest





PostPosted: Sat Jul 09, 2005 3:45 am    Post subject: Re: The Return Value Optimisation Reply with quote


"Guy Davidson" <guy.davidson (AT) hatcat (DOT) com> wrote

Quote:
Is the Return Value Optimisation available to non-inlined functions?

Yes, at least it is with better quality compilers.

Quote:
My code shop is very keen to avoid passing by value. Rather than
something
like this:

big_class foo(int p1, int p2)
{
return big_class(p1, p2);
}

void bar()
{
int p1 = 0;
int p2 = 1;
big_class bc(foo(p1, p2));
}

Digital Mars C++ has been doing this optimization for 15 years at least. The
result is constructed directly into bc, as can be seen in the assembler
output:

?foo@@YA?AUbig_class@@HH@Z:
push dword ptr 0Ch[ESP]
push dword ptr 0Ch[ESP]
mov ECX,0Ch[ESP]
call near ptr ??0big_class@@QAE@HH@Z
ret
?bar@@YAXXZ:
enter 050h,0
xor EAX,EAX
mov ECX,1
push ECX
push EAX
lea EDX,-050h[EBP]
push EDX
call near ptr ?foo@@YA?AUbig_class@@HH@Z
add ESP,0Ch
leave
ret

[[With the addition of a definition of big_class that looks like:

struct big_class
{
int foo[20];

big_class(int, int);
big_class(const big_class&);
};
]]

-Walter
www.digitalmars.com free C, C++, D compilers



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Walter
Guest





PostPosted: Sat Jul 09, 2005 3:45 am    Post subject: Re: The Return Value Optimisation Reply with quote


"Greg" <greghe (AT) pacbell (DOT) net> wrote

Quote:
With its return value now named, the NRVO can be applied, meaning that
a call to foo would effectively construct a big_class in place at the
call site.

A name is not necessary for the optimization to be applied.

-Walter
www.digitalmars.com free C, C++, D compilers



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Gene Bushuyev
Guest





PostPosted: Sat Jul 09, 2005 3:46 am    Post subject: Re: The Return Value Optimisation Reply with quote

"Guy Davidson" <guy.davidson (AT) hatcat (DOT) com> wrote

Quote:
Is the Return Value Optimisation available to non-inlined functions?

Yes, with a but. Abilities to do RVO vary from compiler to compiler, and a
number of popular compilers score poorly in this department.

Quote:

My code shop is very keen to avoid passing by value. Rather than
something
like this:

big_class foo(int p1, int p2)
{
return big_class(p1, p2);
}

But if big_class class is really big, what's the point of moving it from
place to place on the stack, and possibly never having a home for it? You
might find it more convenient (and efficient) creating it on the free store
and using auto_ptr (or some sort of smart pointer) to pass it around.

Gene


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Pablo Halpern
Guest





PostPosted: Sat Jul 09, 2005 3:47 am    Post subject: Re: The Return Value Optimisation Reply with quote

"Greg" <greghe (AT) pacbell (DOT) net> wrote:

Quote:
The Named Return Value Optimization does not rely on function inlining
(it would not be much of optimization if it did). But it does require
that the function always return the same object and that the object
returned be named.

Technically true, but you are confusing the issues. NRVO is a special
case of RVO. The question was about RVO, which does not required a
named value.

Quote:
Since the first function foo in the example above returns an anonymous
big_class object, it fails to meet the latter requirement, and would
not be a candidate for NRVO.

Of course not, but it is a fine candidate for RVO. In fact, most
compilers will do the optimization.

Quote:

A simple change quickly remedies the situation:

big_class foo(int p1, int p2)
{
big_class functionResult(p1, p2);

return functionResult;
}

With its return value now named, the NRVO can be applied, meaning that
a call to foo would effectively construct a big_class in place at the
call site.

No, your "remedy" will make things worse. A limited test shows that Sun
CC does not perform the optimization in your modified code but does
perform it in the original. g++ optimises in both cases.

Quote:
Note also that the NRVO can be applied through a series of nested
function calls - were foo to call another function to obtain
functionResult and the function called had also been NRVO'd, then the
object returned by the innermost function would effectively be
constructed at the calling site two (or more) levels higher in the
calling chain.

The important thing to remember about RVO is that it is an optimization.
As such, you should concern yourself with it under only two conditions:

1. Excessive constructor calls are proving to be a bottleneck in your
code OR

2. Eliding constructor calls breaks your code. In this case, you need
to take special precautions to avoid the RVO. This could be an issue
if, for example, the object being returned contains a pointer to a local
resource and you are counting on a deep copy to disconnect the copy from
the original resource. There are also legitimate reasons for a
constructor or destructor to have side-effects, and the RVO could cause
those side-effects to not take place.

Pablo Halpern [email]phalpern (AT) halpernwightsoftware (DOT) com[/email]
Author: The C++ Standard Library from Scratch
http://www.halpernwightsoftware.com/stdlib-scratch

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
liftmaster
Guest





PostPosted: Tue Jul 12, 2005 3:24 pm    Post subject: Re: The Return Value Optimisation Reply with quote

------------- GREG SEZ:
The Named Return Value Optimization does not rely on function inlining
(it would not be much of optimization if it did). But it does require
that the function always return the same object and that the object
returned be named.
----------

the returned object must be named: really?
that's awful. terrible. why? surely you would expect objects created on
the return line to be optimised away better than any other.

I don't want to go 'round naming objects just so they can be optimized but
also it would seem stupid to ignore this.

what is the rationale behind this?




[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
David Abrahams
Guest





PostPosted: Tue Jul 12, 2005 10:41 pm    Post subject: Re: The Return Value Optimisation Reply with quote

"liftmaster" <maninalift (AT) another (DOT) com> writes:

Quote:
------------- GREG SEZ:
The Named Return Value Optimization does not rely on function inlining
(it would not be much of optimization if it did). But it does require
that the function always return the same object and that the object
returned be named.
----------

the returned object must be named: really?
that's awful. terrible. why? surely you would expect objects created on
the return line to be optimised away better than any other.

I don't want to go 'round naming objects just so they can be optimized but
also it would seem stupid to ignore this.

what is the rationale behind this?

Don't worry, "named" is an artificial distinction created by the order
in which things were standardized. There's also an Unnamed RVO. ;-)

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.