views:

109

answers:

8

I'm writing something performance-critical and wanted to know if it could make a difference if I use:

int test( int a, int b, int c )
{
    // Do millions of calculations with a, b, c
}

or

class myStorage
{
public:
  int a, b, c;
};

int test( myStorage values )
{
   // Do millions of calculations with values.a, values.b, values.c
}
  • Does this basically result in similar code? Is there an extra overhead of accessing the class members?

I'm sure that this is clear to an expert in C++ so I won't try and write an unrealistic benchmark for it right now

+5  A: 

The compiler will probably equalize them. If it has any brains at all, it will copy values.a, values.b, and values.c into local variables or registers, which is also what happens in the simple case.

The relevant maxims:

  1. Premature optimization is the root of much evil.

  2. Write it so you can read it at 1am six months from now and still understand what you were trying to do.

  3. Most of the time significant optimization comes from restructuring your algorithm, not small changes in how variables are accessed. Yes, I know there are exceptions, but this probably isn't one of them.

egrunin
I assume the downvote was for being too terse. I've expanded the answer.
egrunin
+1 for maxim #2. Most people don't write readable code nonetheless actually comment (describe) the intent of the operations.
Thomas Matthews
+4  A: 

This sounds like premature optimization.

That being said, there are some differences and opportunities but they will affect multiple calls to the function rather than performance in the function.

First of all, in the second option you may want to pass MyStorage as a constant reference. As a result of that, your compiled code will likely be pushing a single value into the stack (to allow you to access the container), rather than pushing three separate values. If you have additional fields (in addition to a-c), sending MyStorage not as a reference might actually cost you more because you will be invoking a copy constructor and essentially copying all the additional fields. All of this would be costs per-call, not within the function.

If you are doing tons of calculations with a b and c within the function, then it really doesn't matter how you transfer or access them. If you passed by reference, the initial cost might be slightly more (since your object, if passed by reference, could be on the heap rather than the stack), but once accessed for the first time, caching and registers on your machine will probably mean low-cost access. If you have passed your object by value, then it really doesn't matter, since even initially, the values will be nearby on the stack.

For the code you provided, if these are the only fields, there will likely not be a difference. the "values.variable" is merely interpreted as an offset in the stack, not as "lookup one object, then access another address".

Of course, if you don't buy these arguments, just define local variables as the first step in your function, copy the values from the object, and then use these variables. If you realy use them multiple times, the initial cost of this copy wouldn't matter :)

Uri
A: 

No, your cpu would cache the variables you use over and over again.

DaMacc
A: 

I think there are some overhead, but may not be much. Because the memory address of the object will be stored in the stack, which points to the heap memory object, then you access the instance variable.

If you store the variable int in stack, it would be really faster, because the value is already in stack and the machine just go to stack to get it out to calculate:).

It also depends on if you store the class's instance variable value on stack or not. If inside the test(), you do like:

int a = objA.a;
int b = objA.b;
int c = objA.c;

I think it would be almost the same performance

vodkhang
A: 

If you're really writing performance critical code and you think one version should be faster than the other one, write both versions and test the timing (with the code compiled with right optimization switch). You may even want to see the generated assembly codes. A lot of things can affect the speed of a code snippets that are quite subtle, like register spilling, etc.

Chris Henry
A: 

you can also start your function with

int & a = values.a;
int & b = values.b;

although the compiler should be smart enough to do that for you behind the scenes. In general I prefer to pass around structures or classes, this makes it often clearer what the function is meant to do, plus you don't have to change the signatures every time you want to take another parameter into account.

UncleZeiv
+1  A: 

As with your previous, similar question: it depends on the compiler and platform. If there is any difference at all, it will be very small.

Both values on the stack and values in an object are commonly accessed using a pointer (the stack pointer, or the this pointer) and some offset (the location in the function's stack frame, or the location inside the class).

Here are some cases where it might make a difference:

  • Depending on your platform, the stack pointer might be held in a CPU register, whereas the this pointer might not. If this is the case, accessing this (which is presumably on the stack) would require an extra memory lookup.

  • Memory locality might be different. If the object in memory is larger than one cache line, the fields are spread out over multiple cache lines. Bringing only the relevant values together in a stack frame might improve cache efficiency.

Do note, however, how often I used the word "might" here. The only way to be sure is to measure it.

Thomas
A: 

If you can't profile the program, print out the assembly language for the code fragments.

In general, less assembly code means less instructions to execute which speeds up performance. This is a technique for getting a rough estimate of performance when a profiler is not available.

An assembly language listing will allow you to see differences, if any, between implementations.

Thomas Matthews