performance killer -Debug Iterator Support in Visual studio

Why am I thinking about performance?  Well, because one of my fixes has reduced the performance of the Standard Library.  Before you scream in agony, let me explain…

 

In my first VCBlog post, I mentioned that I was working on something which has since been checked into Orcas (VC9).  I call it The Swap Fix.  To recap, Visual Studio 2005 (VC8) introduced new iterator debugging and iterator checking features.  Iterator debugging, enabled by _HAS_ITERATOR_DEBUGGING, performs powerful correctness verification.  Iterator checking, enabled by _SECURE_SCL, performs minimal checks that serve as a last line of security defense.  For example, _SECURE_SCL will terminate a program that triggers a heap overrun with a vector iterator.

 

All that is explained by MSDN documentation.  The story behind this is interesting.  The _HAS_ITERATOR_DEBUGGING functionality was provided by Dinkumware, the company that licenses their most triumphant implementation of the Standard Library for inclusion in Visual Studio.  The _SECURE_SCL functionality was added by Microsoft, in order to improve the security of programs running on Windows.  In order to perform their checks, both _HAS_ITERATOR_DEBUGGING and _SECURE_SCL make iterators contain additional data members, such as pointers to their parent containers.  _HAS_ITERATOR_DEBUGGING, because it is enabled by default in debug mode (and not obtainable in release mode), also builds singly linked lists that allow containers to refer to all of their iterators.  This is expensive performance-wise, but performance is not critical in debug mode, and this enables excellent checks.

 

_SECURE_SCL, because it is enabled by default in release mode, strives to impose minimal performance penalties.  Therefore, when it is enabled, although iterators have pointers back to their containers, containers don’t have pointers to their iterators.  (Updating "iterator lists" is too time-consuming for release mode.)

 

Now, VC8 RTM/SP1 had a bug when _HAS_ITERATOR_DEBUGGING was disabled and _SECURE_SCL was enabled (e.g. the default for release mode).  When you have persistent iterators into two containers, and then swap the containers, the Standard requires that the iterators remain valid (23.1/10).  Unfortunately, the parent pointers that _SECURE_SCL added to iterators were broken by such a swap.  (The containers being swapped have no way to find the iterators which point into them.)  Dinkumware’s _HAS_ITERATOR_DEBUGGING is immune to this problem since it can walk the iterator lists and update all of the parent pointers.  This option is not available to _SECURE_SCL.

 

In order to fix this conformance bug, The Swap Fix in Orcas makes every Standard container own an additional dynamically allocated object, imaginatively called "the aux object".  Each container holds a pointer to its aux object, which holds a pointer back to the container.  Each iterator, instead of holding a pointer directly to its parent container, now holds a pointer to its parent container’s aux object.  It’s true: everything can be solved by an extra level of indirection.  When containers are swapped, they also swap their aux objects.  This allows the containers to "tell" their iterators their current location, without having to know where they all are.  The result is that VC9 will be conformant even under _SECURE_SCL.

 

The performance issue is that the aux object, while unavoidable (without "pimpling" the containers, which would probably be even more expensive for performance), is not free.  Each Standard container is now larger because it has to hold a pointer to its aux object.  The aux object has to be dynamically allocated, occupying more space and taking more time.  And _SECURE_SCL has perform a double indirection when going from an iterator to its parent container.  I’ve measured the cost of the double indirection, and it is nontrivial: programs that use iterators in deeply nested loops may run at half the speed as before.  (In general, only hand-written loops will be significantly affected.  The Standard algorithms perform checking once and then "uncheck" their arguments for increased speed.  It’s yet another reason to avoid hand-written loops!)  Most programs should not experience noticeable performance changes because of this fix, and some programmers’ lives will be made easier because of the increased conformance, but other programmers will have to deal with the fallout of The Swap Fix.  That’s why I write it with capital letters.

 

This is something to keep in mind: although performance is important, it is not all-important.  Correctness and security trump performance.  _SECURE_SCL increases security, and this fix is necessary to restore correctness.  The performance in VC8 was an illusion, since it was obtained at the cost of correctness.  Orcas’s performance will reflect the true cost of _SECURE_SCL.  As before, programs will be able to turn off _SECURE_SCL in order to extract maximum performance.  How to disable _SECURE_SCL (and _HAS_ITERATOR_DEBUGGING) properly might be a topic for a future blog post – it’s easy to do incorrectly, and we’re thinking about ways to make this process more robust in Orcas + 1.

 

STL

 

http://blogs.msdn.com/vcblog/archive/2007/08/10/the-future-of-the-c-language.aspx

 

"VC9 has several important conformance fixes.  Aside from the Swap Fix, there’s also the iterators-living-beyond-their-containers crash under /MDd (or /MTd) /D_HAS_ITERATOR_DEBUGGING=0.  That was a regression introduced in VC8 SP1.  Fixing it also improved performance.  And that’s just in the libraries – the compiler is getting a very nice fix that significantly improves compilation speed with PCHs and templates."

 

Turning on the Checked Iterators makes the stl code alot slower. profiling the debug build will show that

std::_lockit , std::_Orphan_Me etc. … are the most expensive calls in stl heave applications.

This entry was posted in Uncategorized. Bookmark the permalink.

Leave a comment