Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r51743 - trunk/boost/function
From: dgregor_at_[hidden]
Date: 2009-03-13 01:23:54


Author: dgregor
Date: 2009-03-13 01:23:53 EDT (Fri, 13 Mar 2009)
New Revision: 51743
URL: http://svn.boost.org/trac/boost/changeset/51743

Log:
Implement an optimization that David Abrahams and myself came up with,
where Boost.Function uses a bit in the vtable pointer to indicate when
the target function object has a trivial copy constructor, trivial
destructor, and fits within the small object buffer. In this case, we
just copy the bits of the function object rather than performing an
indirect call to the manager.

This results in a 60% speedup on a micro-benchmark that copies and
calls such function objects repeatedly.

Text files modified:
   trunk/boost/function/function_base.hpp | 18 +++++++++++--
   trunk/boost/function/function_template.hpp | 53 ++++++++++++++++++++++++++++++---------
   2 files changed, 55 insertions(+), 16 deletions(-)

Modified: trunk/boost/function/function_base.hpp
==============================================================================
--- trunk/boost/function/function_base.hpp (original)
+++ trunk/boost/function/function_base.hpp 2009-03-13 01:23:53 EDT (Fri, 13 Mar 2009)
@@ -18,6 +18,9 @@
 #include <typeinfo>
 #include <boost/config.hpp>
 #include <boost/assert.hpp>
+#include <boost/integer.hpp>
+#include <boost/type_traits/has_trivial_copy.hpp>
+#include <boost/type_traits/has_trivial_destructor.hpp>
 #include <boost/type_traits/is_const.hpp>
 #include <boost/type_traits/is_integral.hpp>
 #include <boost/type_traits/is_volatile.hpp>
@@ -625,7 +628,7 @@
     if (!vtable) return typeid(void);
 
     detail::function::function_buffer type;
- vtable->manager(functor, type, detail::function::get_functor_type_tag);
+ get_vtable()->manager(functor, type, detail::function::get_functor_type_tag);
     return *type.type.type;
   }
 
@@ -638,7 +641,7 @@
       type_result.type.type = &typeid(Functor);
       type_result.type.const_qualified = is_const<Functor>::value;
       type_result.type.volatile_qualified = is_volatile<Functor>::value;
- vtable->manager(functor, type_result,
+ get_vtable()->manager(functor, type_result,
                       detail::function::check_functor_type_tag);
       return static_cast<Functor*>(type_result.obj_ptr);
     }
@@ -656,7 +659,7 @@
       type_result.type.type = &typeid(Functor);
       type_result.type.const_qualified = true;
       type_result.type.volatile_qualified = is_volatile<Functor>::value;
- vtable->manager(functor, type_result,
+ get_vtable()->manager(functor, type_result,
                       detail::function::check_functor_type_tag);
       // GCC 2.95.3 gets the CV qualifiers wrong here, so we
       // can't do the static_cast that we should do.
@@ -702,6 +705,15 @@
 #endif
 
 public: // should be protected, but GCC 2.95.3 will fail to allow access
+ detail::function::vtable_base* get_vtable() const {
+ return reinterpret_cast<detail::function::vtable_base*>(
+ reinterpret_cast<std::size_t>(vtable) & ~(std::size_t)0x01);
+ }
+
+ bool has_trivial_copy_and_destroy() const {
+ return reinterpret_cast<std::size_t>(vtable) & 0x01;
+ }
+
   detail::function::vtable_base* vtable;
   mutable detail::function::function_buffer functor;
 };

Modified: trunk/boost/function/function_template.hpp
==============================================================================
--- trunk/boost/function/function_template.hpp (original)
+++ trunk/boost/function/function_template.hpp 2009-03-13 01:23:53 EDT (Fri, 13 Mar 2009)
@@ -678,6 +678,11 @@
               R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>
       vtable_type;
 
+ vtable_type* get_vtable() const {
+ return reinterpret_cast<vtable_type*>(
+ reinterpret_cast<std::size_t>(vtable) & ~(std::size_t)0x01);
+ }
+
     struct clear_type {};
 
   public:
@@ -757,7 +762,7 @@
       if (this->empty())
         boost::throw_exception(bad_function_call());
 
- return static_cast<vtable_type*>(vtable)->invoker
+ return get_vtable()->invoker
                (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS);
     }
 #else
@@ -847,7 +852,8 @@
     void clear()
     {
       if (vtable) {
- reinterpret_cast<vtable_type*>(vtable)->clear(this->functor);
+ if (!this->has_trivial_copy_and_destroy())
+ get_vtable()->clear(this->functor);
         vtable = 0;
       }
     }
@@ -876,8 +882,11 @@
     {
       if (!f.empty()) {
         this->vtable = f.vtable;
- f.vtable->manager(f.functor, this->functor,
- boost::detail::function::clone_functor_tag);
+ if (this->has_trivial_copy_and_destroy())
+ this->functor = f.functor;
+ else
+ get_vtable()->base.manager(f.functor, this->functor,
+ boost::detail::function::clone_functor_tag);
       }
     }
 
@@ -903,8 +912,15 @@
       static vtable_type stored_vtable =
         { { &manager_type::manage }, &invoker_type::invoke };
 
- if (stored_vtable.assign_to(f, functor)) vtable = &stored_vtable.base;
- else vtable = 0;
+ if (stored_vtable.assign_to(f, functor)) {
+ std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base);
+ if (boost::has_trivial_copy_constructor<Functor>::value &&
+ boost::has_trivial_destructor<Functor>::value &&
+ detail::function::function_allows_small_object_optimization<Functor>::value)
+ value |= (std::size_t)0x01;
+ vtable = reinterpret_cast<detail::function::vtable_base *>(value);
+ } else
+ vtable = 0;
     }
 
     template<typename Functor,typename Allocator>
@@ -930,8 +946,15 @@
       static vtable_type stored_vtable =
         { { &manager_type::manage }, &invoker_type::invoke };
 
- if (stored_vtable.assign_to_a(f, functor, a)) vtable = &stored_vtable.base;
- else vtable = 0;
+ if (stored_vtable.assign_to_a(f, functor, a)) {
+ std::size_t value = reinterpret_cast<std::size_t>(&stored_vtable.base);
+ if (boost::has_trivial_copy_constructor<Functor>::value &&
+ boost::has_trivial_destructor<Functor>::value &&
+ detail::function::function_allows_small_object_optimization<Functor>::value)
+ value |= (std::size_t)0x01;
+ vtable = reinterpret_cast<detail::function::vtable_base *>(value);
+ } else
+ vtable = 0;
     }
 
     // Moves the value from the specified argument to *this. If the argument
@@ -947,9 +970,12 @@
 #endif
         if (!f.empty()) {
           this->vtable = f.vtable;
- f.vtable->manager(f.functor, this->functor,
- boost::detail::function::move_functor_tag);
- f.vtable = 0;
+ if (this->has_trivial_copy_and_destroy())
+ this->functor = f.functor;
+ else
+ get_vtable()->base.manager(f.functor, this->functor,
+ boost::detail::function::move_functor_tag);
+ f.vtable = 0;
 #if !defined(BOOST_NO_EXCEPTIONS)
         } else {
           clear();
@@ -979,13 +1005,14 @@
   template<typename R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_PARMS>
   typename BOOST_FUNCTION_FUNCTION<
       R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>::result_type
- BOOST_FUNCTION_FUNCTION<R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>
+ inline
+ BOOST_FUNCTION_FUNCTION<R BOOST_FUNCTION_COMMA BOOST_FUNCTION_TEMPLATE_ARGS>
   ::operator()(BOOST_FUNCTION_PARMS) const
   {
     if (this->empty())
       boost::throw_exception(bad_function_call());
 
- return reinterpret_cast<const vtable_type*>(vtable)->invoker
+ return get_vtable()->invoker
              (this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS);
   }
 #endif


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk