views:

309

answers:

6

The rule of thumb is that it is okay to pass small structs by value and larger ones should be done pointers.

My question is where exactly is this cutoff point? How large can the structures be before you are better off passing them by pointer.

I know this will vary between platforms, but I assume some rough estimates could be given. A year or two ago I tried to figure out this on the PPC architecture and found to my surprise that one could pass quite a lot of data efficiently by value. Think 10 double values or so was just fine due to the large number of registers in PPC. By pointer actually involved more copying in and out of memory.

However I now I am on intel and I expect things could be different. Since the CPU don't have that many registers traditionally, but perhaps that is different on 64bit or floating point registers?

+6  A: 

If you search the web you'll find some guidelines about byte size for passing by reference and value. I would trust pretty much none of it. The only way to know that a particular struct is a problem is to

Profile It

This is the only way to know 100% that there is a problem.

Before the naysayers jump in. Yeah there are some obvious cases out there. I would not for instance ever pass a struct by value if it had say 100 members. But that wouldn't be for performance issues, it would be more for stack space problems.

JaredPar
A: 

Don't neglect the part that alignment plays in your testing. If you're passing floats or doubles around and your structures aren't aligned on appropriate boundaries, the processor may wind up fetching part of your value, shifting it, then ORing the rest in before storing it. I think most modern compilers will DTRT (by aligning the struct when it's declared), but if you're optimizing for space then this will likely be an issue.

Hmmm, now that I think about it, take this with a grain of salt, as I haven't done any low-level coding on the x86 arch since the Pentium Pro...

TMN
A: 

Some compilers may make the optimal size determination for you. If I remember correctly, the TI28xx compiler automatically converts pass by value to pass by reference if the structure is above a certain size.

AShelly
+1  A: 

In C++ there's the rule to pass everything not on the following list as const reference because the performanceis essentially never worse. The list of exceptions is:

  • elementary types (int etc.),
  • pointers,
  • empty types (tag types),
  • function-like types (functors), and
  • iterators.

I'm not sure if this can be applied directly to C (apart from the obvious types that C doesn't have) but maybe a similar guideline applies.

Konrad Rudolph
Adam Smith
Access to pointers of course incurs an overhead but processor manufacturers are aware of the necessity of pointers. As such, they take precautions. The AMD optimization guide for example explicity advises using pointers here because the processor is developed with such usage in mind. Long story short: even for small structs, pointers might well be faster than pass-by-value. Inlining can of course modify this behaviour further.
Konrad Rudolph
A: 

Usually primitive types I pass by value, everything else by reference. That's my rule of the thumb.

simao
Question is about performance, not about your rules.
stepancheg
A: 

Okay, so I tried to follow advice and profile my code with using pointers and value. I also looked at the assembly code. It seems that the performance characteristics on x86 are quite different from PPC. On PPC the binary interface to C specified that arguments would be put into registers (there were so many to chose from), however it seems that even on 64bit x86 requires arguments to be put on the stack.

So that explains why on x86 passing by pointer always seems to be faster. However I noticed the compiler is very eager to inline. So it didn't matter in which way I did it. So I guess the conclusion is to use whatever passing which is convenient to you.

I think that favors pass by value, because working on copies of values is somewhat safer. My test case was a struct consisting of 4 doubles (so I guess that makes it 32 bytes on most platforms).

Adam Smith