Can pointer wrappers increase performance by making compiler analysis easier?

Started by
6 comments, last by L. Spiro 10 years, 6 months ago

Let's say I have a class that is just a thin wrapper over a pointer and the only thing the class does is call delete in the destructor like an auto pointer.However, it also has an operator that automatically dereferences, so I can pass it around in functions that take const references and then I make as much as my functions as possible to take in const references.I have 3 questions about this scenario:

1.Is it certain that the compiler(MSVC in release mode with all possible optimizations enabled) will inline every wrapper method and allow the pointer to have the same performance as a raw pointer?(It's hard to benchmark pointers since I get a lot of memory fragmentation when I test different types, so I'm not sure how to test them, but I've seen 100% identical performance between my array container and raw arrays, so I assume this should happen to the pointer wrapper too with exception to the part where it gets deleted when it goes out of scope)

2.Will the compiler optimize away the useless dereferencing from the wrapper's opereator if/when it realizes they're passed by references(which are basically pointers again)

3.Will passing everything around as const references improve performance?A lot of sources, like this for instance ftp://ftp.sgi.com/sgi/audio/audio.apps/dev/aliasing.html talk about how you can make the compiler's job easier by pretty much restricting and/or constifying inputs everywhere.(maybe I'm not getting it right).

Also it's extremely convenient not to have to manually delete every member in the destructor when you use the auto pointer for class members.I'm just worried about the performance impact.

>removed<

Advertisement

1.Is it certain that the compiler(MSVC in release mode with all possible optimizations enabled) will inline every wrapper method and allow the pointer to have the same performance as a raw pointer?(It's hard to benchmark pointers since I get a lot of memory fragmentation when I test different types, so I'm not sure how to test them, but I've seen 100% identical performance between my array container and raw arrays, so I assume this should happen to the pointer wrapper too with exception to the part where it gets deleted when it goes out of scope)

Inlining is never certain.
But there is a very high probability, as long as you have implemented them in the header file.

2.Will the compiler optimize away the useless dereferencing from the wrapper's opereator if/when it realizes they're passed by references(which are basically pointers again)

References and pointers are the same thing to the compiler, however a built-in reference has restrictions, and restrictions typically allow potential optimizations, particularly related to aliasing in this case. It’s only guesswork as to which compilers will decide to optimize anything, when, and where, if at all, though.

3.Will passing everything around as const references improve performance?A lot of sources, like this for instance ftp://ftp.sgi.com/sgi/audio/audio.apps/dev/aliasing.html talk about how you can make the compiler's job easier by pretty much restricting and/or constifying inputs everywhere.(maybe I'm not getting it right).

Having only “const” references is stupid. const exists to indicate something as read-only. Using const in a non-const situation just because you only return const references is just abusing the language and will gain you nothing. The compiler still has to view it as non-const if it allows modifying it.
“const” tends only to help in terms of performance when aliasing is concerned, in that the compiler can be assured (under assumptions of a competent coder) to incoming pointers of the same type, one const and one not, will not reference the same memory (even though they might).


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

3.Will passing everything around as const references improve performance?A lot of sources, like this for instance ftp://ftp.sgi.com/sgi/audio/audio.apps/dev/aliasing.html talk about how you can make the compiler's job easier by pretty much restricting and/or constifying inputs everywhere.(maybe I'm not getting it right).

The const-qualifier in C++ doesn't help the compiler in making better optimizations. The compiler cannot assume that:

a) const-qualified variables are really never written to (after all, there's const_cast<>) and

b) that variables marked "const" don't alias.

"const" is there to prevent programmers from accidentally writing to data which is supposed to be read-only. Additionally, it serves as a kind of documentation or contract (if used correctly) to other programmers that use the API.

What really helps compiler optimizations is using the restrict keyword (a C99 keyword, understood by most C++ compilers) on pointers and class methods. Note that restrict-ing something is a promise to the compiler, though. If you break your promise, the code won't behave correctly, and can lead to hard-to-find bugs. Check this article for more information.

One final thing: with the restrict keyword, it doesn't matter whether the restricted pointers are const-qualified or not. After all, "restrict" promises that variables don't alias, hence read-only or write-access don't really play a role here.

a) const-qualified variables are really never written to (after all, there's const_cast<>) and


I do not think that is true. Unfortunately I don't have the standard in reach right now but a quick googling reinforces my suspicion:
"Even though const_cast may remove constness from any pointer or reference, using the resulting pointer or reference to write to an object that was declared const invokes undefined behavior."

Using const_cast to write to an object that was created with const is undefined behavior, but const_cast isn't really the reason that const references aren't very useful for optimization. It's the fact that you can have a const reference to a non-const object. Since there's no way for a compiler to know if the const reference is a reference to a really const object, it can't make any assumptions about the mutability of an object referred to through a const reference.

OK I made some tests and the results were surprising:
1.I tested raw pointer to some struct versus the pointer wrapper by passing their values to the methods of some other class.In case 1 I pass the raw pointer and the method takes a raw pointer as an argument.In case 2 the method takes a const reference of the struct as an argument and the pointer wrapper class automatically passes it as a reference when I write it in the argument.
Strangely, the wrapper class outperformed the raw pointer EVERY TIME.

2.I tested setting and getting members with the -> operator.Raw pointer wins here by a huge amount.It seems the overloaded -> operator doesn't get inlined no matter what?!

I was running in release mode with every possible optimization enabled, not sure how to explain what happens.I'm no good at reading assembly listing so I'm not sure how to explain that.

>removed<


It's the fact that you can have a const reference to a non-const object. Since there's no way for a compiler to know if the const reference is a reference to a really const object, it can't make any assumptions about the mutability of an object referred to through a const reference.

+1, much better said than I could ever say it. That's what I meant: you can have a const-reference to a non-const object, so casting away const using a const_cast allows you to mutate the original object - hence there's no optimization opportunity for the compiler there.

OK I made some tests and the results were surprising:
1.I tested raw pointer to some struct versus the pointer wrapper by passing their values to the methods of some other class.In case 1 I pass the raw pointer and the method takes a raw pointer as an argument.In case 2 the method takes a const reference of the struct as an argument and the pointer wrapper class automatically passes it as a reference when I write it in the argument.
Strangely, the wrapper class outperformed the raw pointer EVERY TIME.

2.I tested setting and getting members with the -> operator.Raw pointer wins here by a huge amount.It seems the overloaded -> operator doesn't get inlined no matter what?!

I was running in release mode with every possible optimization enabled, not sure how to explain what happens.I'm no good at reading assembly listing so I'm not sure how to explain that.

When doing performance tests, be sure to do tests that create a side-affect and then use that side-affect in a debug message.
If the compiler sees no side-affects in a section of code it will often eliminate it entirely.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

This topic is closed to new replies.

Advertisement