Enabling fast swap optimization for Boost types VC9 SP1.

The VC team recently released an update to the VC9 standard library that allows them to take advantage of types with fast swap when performing operations like vector realloc. However it appears this optimization is guarded by a trait that must be specialized. Could we specialize std::_Move_operation_category for this version of VC9 to enable this optimization for boost types that can benefit from it? http://tinyurl.com/6h298c Thanks, Michael Marcin

Michael Marcin wrote:
The VC team recently released an update to the VC9 standard library that allows them to take advantage of types with fast swap when performing operations like vector realloc. However it appears this optimization is guarded by a trait that must be specialized.
Could we specialize std::_Move_operation_category for this version of VC9 to enable this optimization for boost types that can benefit from it?
I try to stay away from the preprocessor so maybe someone can take this an extend it but how about something like: #if defined(_MSC_VER) # if( _MSC_FULL_VER == 150030729 && _MSC_BUILD == 1 ) // enables fast swap optimization for vc9 sp1 # include <xutility> # define BOOST_MSVC_FAST_SWAP_OPTIMIZATION( Class, Arg ) \ namespace std \ { \ template< class Arg > \ class _Move_operation_category< Class< Arg > > \ { \ public: \ typedef _Swap_move_tag _Move_cat; \ }; \ } # elif defined(BOOST_DETECT_OUTDATED_WORKAROUNDS) && (_MSC_FULL_VER > 150030729) # error "MSVC version is newer than VC9 SP1 if the fast swap optimization still needs to be enabled update the version numbers" # endif #endif #if !defined(BOOST_MSVC_FAST_SWAP_OPTIMIZATION) # define BOOST_MSVC_FAST_SWAP_OPTIMIZATION( Class, Args ) #endif Then take for instance boost/shared_ptr.hpp and add BOOST_MSVC_FAST_SWAP_OPTIMIZATION( boost::shared_ptr, T ) Thanks, Michael Marcin

Michael Marcin a écrit :
Then take for instance boost/shared_ptr.hpp and add
BOOST_MSVC_FAST_SWAP_OPTIMIZATION( boost::shared_ptr, T )
I was under the impression that with VC9 SP1, boost::shared_ptr would just be an alias to std::tr1::shared_ptr. Am I wrong ? -- Loïc

Loïc Joly:
I was under the impression that with VC9 SP1, boost::shared_ptr would just be an alias to std::tr1::shared_ptr.
No, boost::shared_ptr is never an alias. You can use the Boost.TR1 wrapper library to get an std::tr1::shared_ptr that is either native (if the compiler provides one) or an alias of boost::shared_ptr.

Loïc Joly wrote:
Michael Marcin a écrit :
Then take for instance boost/shared_ptr.hpp and add
BOOST_MSVC_FAST_SWAP_OPTIMIZATION( boost::shared_ptr, T )
I was under the impression that with VC9 SP1, boost::shared_ptr would just be an alias to std::tr1::shared_ptr. Am I wrong ?
The boost shared_ptr has a different implementation and some extensions that the tr1 shared_ptr doesn't have. Like make_shared for instance. I have code that uses a lot of boost::shared_ptr and there are some things that are just broken in vc9's tr1 implementation. You can't store tr1 functions in a std::container for instance because of a bug. I would really like to get the no copy no throw container manipulation for things like boost::function and boost::shared_ptr and all it takes is a simple trait specialization. I could do these myself in a precompiled header or something but they seem like optimizations that are so trivial and useful that they should go into boost so everyone can benefit from them. Thanks, Michael Marcin

Michael Marcin wrote:
Could we specialize std::_Move_operation_category for this version of VC9 to enable this optimization for boost types that can benefit from it? http://tinyurl.com/6h298c
Thanks for the link! I just did some promotion of the new boost::swap utility at the blogs.msdn.com/vcblog site :-) Shouldn't this MSVC optimization be enabled for /any/ type that has a custom swap function? Typically such a type has a swap member function as well. So can't this std::_Move_operation_category be specialized based on some template meta programming (e.g., has_swap_member<T>::value)? Such an approach looks preferable to me than adding a macro call (BOOST_MSVC_FAST_SWAP_OPTIMIZATION) for each type that has a custom swap.
I have code that uses a lot of boost::shared_ptr and there are some things that are just broken in vc9's tr1 implementation. You can't store tr1 functions in a std::container for instance because of a bug. I would really like to get the no copy no throw container manipulation for things like boost::function and boost::shared_ptr and all it takes is a simple trait specialization.
Please note that the current version of boost::function::swap is /less/ efficient than doing a single copy. A few months ago, I submitted a ticket on this issue, triggered by a posting from Arvid Norberg here at [boost]: http://svn.boost.org/trac/boost/ticket/1910 Kind regards, -- Niels Dekker http://www.xs4all.nl/~nd/dekkerware Scientific programmer at LKEB, Leiden University Medical Center

on Fri Aug 22 2008, "Niels Dekker - mail address until 2008-12-31" <nd_mail_address_valid_until_2008-12-31-AT-xs4all.nl> wrote:
Michael Marcin wrote:
Could we specialize std::_Move_operation_category for this version of VC9 to enable this optimization for boost types that can benefit from it? http://tinyurl.com/6h298c
Thanks for the link! I just did some promotion of the new boost::swap utility at the blogs.msdn.com/vcblog site :-)
Shouldn't this MSVC optimization be enabled for /any/ type that has a custom swap function? Typically such a type has a swap member function as well. So can't this std::_Move_operation_category be specialized based on some template meta programming (e.g., has_swap_member<T>::value)? Such an approach looks preferable to me than adding a macro call (BOOST_MSVC_FAST_SWAP_OPTIMIZATION) for each type that has a custom swap.
I don't know what member functions have to do with it; the real criterion is whether or not there's a swap available for it via ADL. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

So can't this std::_Move_operation_category be specialized based on some template meta programming (e.g., has_swap_member<T>::value)?
David Abrahams wrote:
I don't know what member functions have to do with it; the real criterion is whether or not there's a swap available for it via ADL.
Thanks, Dave! I knew how to write has_swap_member<T> already, but I didn't yet know about has_swap_overload<T>. Now I see, it's also at http://svn.boost.org/svn/boost/sandbox/move/boost/move/detail/has_swap_overl... I just added another comment to the MSDN blog, mentioned your metafunction: http://blogs.msdn.com/vcblog/archive/2008/08/11/tr1-fixes-in-vc9-sp1.aspx It's a pity that has_swap_overload<T> yields false negatives, when T has std as associated namespace. Maybe, as a workaround, VC9 SP1 could be tweaked to apply their "Swaptimization", when has_swap_overload<T> /or/ has_swap_member<T> (using mpl::or_). Because I still think that if T has a swap member function, it's /very/ likely that it has a custom swap overload as well. Assuming that developers follow the "coding standard" to provide a non-member swap, whenever they provide a swap member function. What do you think? Kind regards, Niels

on Sat Aug 23 2008, Niels Dekker - mail address until 2008-12-31 <nd_mail_address_valid_until_2008-12-31-AT-xs4all.nl> wrote:
So can't this std::_Move_operation_category be specialized based on some template meta programming (e.g., has_swap_member<T>::value)?
David Abrahams wrote:
I don't know what member functions have to do with it; the real criterion is whether or not there's a swap available for it via ADL.
Thanks, Dave! I knew how to write has_swap_member<T> already, but I didn't yet know about has_swap_overload<T>. Now I see, it's also at http://svn.boost.org/svn/boost/sandbox/move/boost/move/detail/has_swap_overl...
I think that might be an older version of the same functionality. In fact, I think I forgot about the old version when I posted the one I did. So you might compare and see if one is better.
I just added another comment to the MSDN blog, mentioned your metafunction: http://blogs.msdn.com/vcblog/archive/2008/08/11/tr1-fixes-in-vc9-sp1.aspx
It's a pity that has_swap_overload<T> yields false negatives, when T has std as associated namespace.
It's easy enough to fix that with specialization, as my posted example shows.
Maybe, as a workaround, VC9 SP1 could be tweaked to apply their "Swaptimization", when has_swap_overload<T> /or/ has_swap_member<T> (using mpl::or_). Because I still think that if T has a swap member function, it's /very/ likely that it has a custom swap overload as well.
Well, now, that's not a bad point.
Assuming that developers follow the "coding standard" to provide a non-member swap, whenever they provide a swap member function. What do you think?
IMO the best solution is like this: std is an associated namespace of T ? has_member_swap<T> : has_nonmember_swap<T> plus any specializations required to handle something like tr1::array that might not have a member swap. Rationale: if std is not an associated namespace and the nonmember swap doesn't exist, then using std::swap; swap(x, y) won't be optimized. Thoughts? -- Dave Abrahams BoostPro Computing http://www.boostpro.com

David Abrahams wrote:
http://svn.boost.org/svn/boost/sandbox/move/boost/move/detail/has_swap_overl... I think that might be an older version of the same functionality. In fact, I think I forgot about the old version when I posted the one I did. So you might compare and see if one is better.
It's actually the other way around: The version that Daniel James added to svn/boost/sandbox/move is the better one. It has three more has_swap_overload specializations: for std::basic_string, std::multiset, and std::multimap. And it has the std forward declarations included from <boost/functional/detail/container_fwd.hpp>.
It's a pity that has_swap_overload<T> yields false negatives, when T has std as associated namespace.
It's easy enough to fix that with specialization, as my posted example shows.
Hmmm... So has_swap_overload<T> should have a specialization for each class template that has a template type parameter (allowing std as associated namespace of the template argument) and a custom swap. That's a pity.
IMO the best solution is like this:
std is an associated namespace of T ? has_member_swap<T> : has_nonmember_swap<T>
plus any specializations required to handle something like tr1::array that might not have a member swap.
FYI, the tr1::array that comes with VC9 SP1 /does/ have a member swap, as well as a swap overload. Anyway, I was also considering a more "lightweight" way to tweak MSVC's Swaptimization, merely based upon tr1::has_nothrow_copy (which is included VC9 SP1). Because when using MSVC9, whenever a function like vector<T>::push_back needs to reallocate, it moves its elements /either/ by copy-construction /or/ by default-construction + swap, depending on whether "Swaptimization" is turned on for type T. Isn't it reasonable to just do default-construction + swap, /unless/ T has no-throw copy-construction? if tr1::has_nothrow_copy<T> move by means of copy else move by means of default-construction + swap Kind regards, Niels

Niels Dekker - mail address until 2008-12-31 wrote:
Anyway, I was also considering a more "lightweight" way to tweak MSVC's Swaptimization, merely based upon tr1::has_nothrow_copy (which is included VC9 SP1). Because when using MSVC9, whenever a function like vector<T>::push_back needs to reallocate, it moves its elements /either/ by copy-construction /or/ by default-construction + swap, depending on whether "Swaptimization" is turned on for type T. Isn't it reasonable to just do default-construction + swap, /unless/ T has no-throw copy-construction?
if tr1::has_nothrow_copy<T> move by means of copy else move by means of default-construction + swap
Unless you have a type like boost::function apparently is currently where default construction + swap is also not a no throw operation and is more expensive than a direct copy. Unless you consider swaps like boost::function's a bug I don't think it is fair to assume swap means fast move in general. I think the only real way to get it right in every case is to have the author of the type specify the proper traits.

Michael Marcin wrote:
I think the only real way to get it right in every case is to have the author of the type specify the proper traits.
Okay, I give up. A generic way to tweak MSVC's "Swaptimization" just doesn't seem feasable without adding a /lot/ of template specializations. See also the reply by Stephan T. Lavavej on my questions at http://blogs.msdn.com/vcblog/archive/2008/08/11/tr1-fixes-in-vc9-sp1.aspx So any type for which default-construction + swap outperforms copy-construction should preferably have "Swaptimization" enabled. Let's call such a type "Swaptimizable". So should we add a specialization of std::_Move_operation_category to each Boost HPP file that defines a "Swaptimizable" type? Or would it be preferable to have a single header file, containing std::_Move_operation_category specializations of for all "Swaptimizable" Boost types? Note that for some templates whether an instantiation is "Swaptimizable" depends upon its template argument. For example, "Swaptimization" should be applied to boost::array<std::string>, but not to boost::array<int>. Kind regards, Niels

Niels Dekker - mail address until 2008-12-31 wrote:
Michael Marcin wrote:
I think the only real way to get it right in every case is to have the author of the type specify the proper traits.
Okay, I give up. A generic way to tweak MSVC's "Swaptimization" just doesn't seem feasable without adding a /lot/ of template specializations.
See also the reply by Stephan T. Lavavej on my questions at http://blogs.msdn.com/vcblog/archive/2008/08/11/tr1-fixes-in-vc9-sp1.aspx
So any type for which default-construction + swap outperforms copy-construction should preferably have "Swaptimization" enabled. Let's call such a type "Swaptimizable". So should we add a specialization of std::_Move_operation_category to each Boost HPP file that defines a "Swaptimizable" type? Or would it be preferable to have a single header file, containing std::_Move_operation_category specializations of for all "Swaptimizable" Boost types?
Note that for some templates whether an instantiation is "Swaptimizable" depends upon its template argument. For example, "Swaptimization" should be applied to boost::array<std::string>, but not to boost::array<int>.
I think that each library including the proper specializations makes the most sense and supports the weakest coupling. Some utility, maybe in config, should probably be created so that libraries can easily enable these swaptimzations for their types. If it is not easy and clean people won't do it and that would be a shame because the VC team has provided us with a customization point to easily achieve some large performance gains.

on Tue Aug 26 2008, "Niels Dekker - mail address until 2008-12-31" <nd_mail_address_valid_until_2008-12-31-AT-xs4all.nl> wrote:
Michael Marcin wrote:
I think the only real way to get it right in every case is to have the author of the type specify the proper traits.
Okay, I give up. A generic way to tweak MSVC's "Swaptimization" just doesn't seem feasable without adding a /lot/ of template specializations.
What was wrong with my proposal? You can't guarantee it will be right every time, but it's easy to correct when wrong, and that would only take a very few specializations. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

David Abrahams wrote:
What was wrong with my proposal?
You can't guarantee it will be right every time, but it's easy to correct when wrong, and that would only take a very few specializations.
Please note: The question is /not/ whether T has a custom swap. The question is whether default-construction + swap outperforms copy-construction for type T. Only in that case, it makes sense to activate "Swaptimization". Anyway, I agree, your approach provides a reasonable first guess:
std is an associated namespace of T ? has_member_swap<T> : has_nonmember_swap<T>
So for such a type T, _Move_operation_category<T>::_Move_cat should be set to "_Swap_move_tag", instead of "_Undefined_move_tag", by default. Do you know how we can technically overrule the default _Move_operation_category<T> provided by MSVC's STL? In ConceptC++, it would look a little bit like this: template <class T> where HasCustomSwap<T> // Pseudo ConceptC++ struct _Move_operation_category<T> { typedef _Swap_move_tag _Move_cat; }; But how to do that in C++03? Kind regards, Niels

on Wed Aug 27 2008, "Niels Dekker - mail address until 2008-12-31" <nd_mail_address_valid_until_2008-12-31-AT-xs4all.nl> wrote:
David Abrahams wrote:
What was wrong with my proposal?
You can't guarantee it will be right every time, but it's easy to correct when wrong, and that would only take a very few specializations.
Please note: The question is /not/ whether T has a custom swap. The question is whether default-construction + swap outperforms copy-construction for type T. Only in that case, it makes sense to activate "Swaptimization".
Of course. But can you come up with a type where it makes sense to have written a custom swap but default-construction + swap won't outperform copy construction? Maybe my imagination is failing me, but I can't.
Anyway, I agree, your approach provides a reasonable first guess:
std is an associated namespace of T ? has_member_swap<T> : has_nonmember_swap<T>
So for such a type T, _Move_operation_category<T>::_Move_cat should be set to "_Swap_move_tag", instead of "_Undefined_move_tag", by default. Do you know how we can technically overrule the default _Move_operation_category<T> provided by MSVC's STL?
Specialization?
In ConceptC++, it would look a little bit like this:
template <class T> where HasCustomSwap<T> // Pseudo ConceptC++ struct _Move_operation_category<T> { typedef _Swap_move_tag _Move_cat; };
But how to do that in C++03?
Ohhh... If they didn't give us any further hooks (such as a default argument) to hang a specialization on, then sadly I don't know of a way. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

David Abrahams wrote:
But can you come up with a type where it makes sense to have written a custom swap but default-construction + swap won't outperform copy construction?
What do you think of the ticket I recently submitted, requesting custom swap functions for value_initialized<T>? http://svn.boost.org/trac/boost/ticket/2243 After having added value_initialized<T>::swap according to the ticket, it would very much depends upon T whether or not default-construction + swap would outperform copy-construction, for value_initialized<T>.
Do you know how we can technically overrule the default _Move_operation_category<T> provided by MSVC's STL?
If they didn't give us any further hooks (such as a default argument) to hang a specialization on, then sadly I don't know of a way.
Their macro _DEFAULT_MOVE_OPERATION_CATEGORY looks a little bit like a hook, but it wasn't intended that way, as Stephan T. Lavavej told me at http://blogs.msdn.com/vcblog/archive/2008/08/11/tr1-fixes-in-vc9-sp1.aspx A related issue: the trunk version of Boost Optional now allows boost::optional<T>::swap to be tweaked in a similar way, following a request by Thorsten, here at [boost]. Optional's swap function uses default-construction + swap when specified by boost::optional_swap_should_use_default_constructor<T>: http://svn.boost.org/svn/boost/trunk/boost/optional/optional.hpp I think it would be preferable to have Optional's swap tweaking based upon the same type traits that activate "Swaptimization" on MSVC's STL. Kind regards, Niels

David Abrahams wrote:
on Wed Aug 27 2008, "Niels Dekker - mail address until 2008-12-31" <nd_mail_address_valid_until_2008-12-31-AT-xs4all.nl> wrote:
David Abrahams wrote:
What was wrong with my proposal?
You can't guarantee it will be right every time, but it's easy to correct when wrong, and that would only take a very few specializations. Please note: The question is /not/ whether T has a custom swap. The question is whether default-construction + swap outperforms copy-construction for type T. Only in that case, it makes sense to activate "Swaptimization".
Of course. But can you come up with a type where it makes sense to have written a custom swap but default-construction + swap won't outperform copy construction? Maybe my imagination is failing me, but I can't.
Isn't this the case for the current boost::function? Also a type could be Swappable and Assignable but not Default Constructible. Thanks, Michael Marcin

There's another update on the Swaptimization issue at the Visual C++ Blog (please scroll to the end): http://blogs.msdn.com/vcblog/archive/2008/08/11/tr1-fixes-in-vc9-sp1.aspx So MSVC's Swaptimization has a few bugs concerning std::pair, tr1::array, tr1::tuple, and tr1::function. Fortunately they're considering a hotfix. Still, if we're going to add Swaptimization support to Boost (by adding _Move_operation_category<T> specializations), we have to realize that it will only be for one specific compiler version: MSVC 9 SP1. MSVC 10 will no longer do Swaptimization. Before SP1, MSVC 9 also supported Swaptimization, but it called std::swap without argument-dependent lookup :-( Only MSVC 9 SP1 does ADL, when calling swap. Michael Marcin wrote:
Unless you consider swaps like boost::function's a bug I don't think it is fair to assume swap means fast move in general.
Did you take a look at the boost::function::swap patch I submitted a few months ago? http://svn.boost.org/trac/boost/ticket/1910 Do you think it would correctly solve the function::swap issue? Kind regards, Niels

on Mon Aug 25 2008, "Niels Dekker - mail address until 2008-12-31" <nd_mail_address_valid_until_2008-12-31-AT-xs4all.nl> wrote:
David Abrahams wrote:
It's a pity that has_swap_overload<T> yields false negatives, when T has std as associated namespace.
It's easy enough to fix that with specialization, as my posted example shows.
Hmmm... So has_swap_overload<T> should have a specialization for each class template that has a template type parameter (allowing std as associated namespace of the template argument) and a custom swap. That's a pity.
What can I say; it's the best we can do.
IMO the best solution is like this:
std is an associated namespace of T ? has_member_swap<T> : has_nonmember_swap<T>
plus any specializations required to handle something like tr1::array that might not have a member swap.
FYI, the tr1::array that comes with VC9 SP1 /does/ have a member swap, as well as a swap overload.
Anyway, I was also considering a more "lightweight" way to tweak MSVC's Swaptimization, merely based upon tr1::has_nothrow_copy (which is included VC9 SP1). Because when using MSVC9, whenever a function like vector<T>::push_back needs to reallocate, it moves its elements /either/ by copy-construction /or/ by default-construction + swap, depending on whether "Swaptimization" is turned on for type T. Isn't it reasonable to just do default-construction + swap, /unless/ T has no-throw copy-construction?
That's a massive pessimization for fundamental types and simple composites: int, T*, pairs, tuples, std::complex, etc... not to mention that has_nothrow_copy *has* to give false negatives, even on a smart compiler. -- Dave Abrahams BoostPro Computing http://www.boostpro.com
participants (5)
-
David Abrahams
-
Loïc Joly
-
Michael Marcin
-
Niels Dekker - mail address until 2008-12-31
-
Peter Dimov