tags:

views:

351

answers:

6

I have do an extensive calculation on a big vector of integers. The vector size is not changed during the calculation. The size of the vector is frequently accessed by the code. What is faster in general: using the vector::size() function or using helper constant vectorSize storing the size of the vector? I know that compilers usually able to inline the size() function when setting the proper compiler flags, however, making a function inline is something that a compiler may do but can not be forced.

+4  A: 

As I understand the 1998 C++ specification, vector<T>::size() takes constant time, not linear time. So, this question likely boils down to whether it's faster to read a local variable than calling a function that does very little work.

I'd therefore claim that storing your vector's size() in a local variable will speed up your program by a small amount, since you'll only call that function (and therefore the small constant amount of time it takes to execute) once instead of many times.

stakx
Steve Jessop
That said, you may well be right that it would be a small speedup, just not because of the inlining issue the questioner is worried about. For instance, maybe `size` hits memory every time (if the compiler can't prove to itself that the size won't change), whereas using a local variable allows the compiler to keep the size in a register (if you have enough registers). You never know, basically.
Steve Jessop
@Steve Jessop: Well pointed out. The real time saving (even if it's very small) of course would result from calling the function only once instead of many times, not from the fact that the function call mechanism itself is more expensive than reading a variable. -- However, I wouldn't want to rely on an optimising compiler to take the function call outside of the loop if I can easily do this myself.
stakx
@David Rodríguez: _"What are you actually doing with [...]?"_ -- You need to ask that the OP, not me.
stakx
+3  A: 

In every implementation I've, seen vector::size() performs a subtraction of end() and begin(), ie its not as fast as reading a variable.

When implementing a vector, the implementer has to make a choice between which shall be fastest, end() or size(), ie storing the number of initialized elements or the pointer/iterator to the element after the last initialized element. In other words; iterate by using iterators.

If you are worried of the size() performance, write your index based for loop like this;

for (size_t i = 0, i_end = container.size(); i < i_end; ++i){
// do something performance critical
}
Viktor Sehr
"In every implementation I've, seen vector::size() performs a subtraction of end() and begin(), ie its not as fast as reading a variable." -- yes but the compiler may still take that outside the loop in theory, or otherwise monkey about with the C++ code you are looking at.
John
A: 

You could write yourself a functor for your loop body and call it via std::for_each. It does the iteration for you, and then your question becomes moot. However, you're introducing a function call (that may or may not get inlined) for every loop iteration, so you'd best profile it if you're not getting the performance you expect.

Kristo
You're asssuming that size() is used just in the loop condition. What if each iteration calls `foo(vec[i], vec.size()-i)` ? You can't make that call using `for_each`.
MSalters
+6  A: 

Performance of vector::size() : is it as fast as reading a variable?

Probably not.

Does it matter

Probably not.

Unless the work you're doing per iteration is tiny (like one or two integer operations) the overhead will be insignificant.

John
+1  A: 

Always get a profile of your application before looking at this sort of micro optimization. Remember that even if it performs a subtraction, the compiler could still easily optimize it in many ways that would negate any performance loss.

DeadMG
+5  A: 

Funny question.

So, what's going to happened ? Well if you debug with gdb you'll see something like 3 member variables (names are not accurate):

  • _M_begin: pointer to the first element of the dynamic array
  • _M_end: pointer one past the last element of the dynamic array
  • _M_capacity: pointer one past the last element that could be stored in the dynamic array

The implementation of vector<T,Alloc>::size() is thus usually reduced to:

return _M_end - _M_begin;  // Note: _Mylast - _Myfirst in VC 2008

Now, there are 2 things to consider when regarding the actual optimizations possible:

  • will this function be inlined ? Probably: I am no compiler writer, but it's a good bet since the overhead of a function call would dwarf the actual time here and since it's templated we have all the code available in the translation unit
  • will the result be cached (ie sort of having an unnamed local variable): it could well be, but you won't know unless you disassemble the generated code

In other words:

  • If you store the size yourself, there is a good chance it will be as fast as the compiler could get it...
  • but you expose yourself to maintenance wreck: what if suddenly you modify the vector and don't update the variable ;) ?

Anyhow, I seriously doubt it's worth the hassle. It's a micro-optimization at best, and unlikely to yield much of an improvement.

Matthieu M.
"Will the result be cached?" That's a question which can have 2 answers even within a single function. Compilers are quite good at figuring out whether and where they have enough registers to save an intermediate result.
MSalters
@MSalters: I couldn't agree more. And in particular if the compiler decides there isn't enough space, then introducing a spurious variable may not yield any improvement.
Matthieu M.