
On Thu, Oct 21, 2010 at 2:25 AM, Doug Gregor <doug.gregor@gmail.com> wrote:
On Wed, Oct 20, 2010 at 1:51 PM, Daniel Walker <daniel.j.walker@gmail.com> wrote:
So, adding "empty" vtable objects would increase the space requirements of boost::function; each template instantiation would need two corresponding vtable objects, one for actual targets and one as a fallback that throws bad_function_call. (The "empty" vtable objects could be stored statically, but static storage is also a very precious resource on many platforms.) Not all users would appreciate this trade-off; i.e. an increase in the space overhead for a small decrease in time overhead (with compiler optimization the time savings are minuscule, in my experience).
Without quantifying the trade-off, we don't know which way is better.
In any case, this issue is fairly easy to settle; it just takes effort. Someone implements this alternative scheme and determines the cost/benefit in space and time, and with any luck the choice is obvious.
OK, I implemented the alternative scheme and ran some benchmarks to determine the cost/benefit in space/time. The code is in a Trac ticket with a patch that allows boost::function to be configured to represent its empty state using a static object that contains an "empty" function which calls boost::throw_exception when invoked. The user may select the alternative scheme by defining the macro BOOST_FUNCTION_USE_STATIC_EMPTY. https://svn.boost.org/trac/boost/ticket/4803 I also attached a tarball to the ticket with a Jamfile and source code to compile and run benchmarks of a function pointer, boost::function, and boost::function using the static empty scheme. The time overhead per call and space overhead per object are measured by the executables at runtime. The space overhead per type is the size of the static initialized date section in the executable's data segment as reported by /usr/bin/size. The following results were obtained on a x86 machine running an Unix variant using the manufacture's build of gcc 4.2. The machine was not in a labratory environment, so I am not controlling for changes in operating tempature that could impact performance at these time scales. The following tables present the raw numbers from bjam's release and debug builds. (See the Jamfile for the complete arguments to bjam.) Data (Release): | funcion ptr | function | function (static empty) time/call | 6.28e-10s | 6.68e-09s | 6.40e-09s space/type | 32B | 48B | 64B space/obj | 8B | 32B | 32B Result (Release): Defining BOOST_FUNCTION_USE_STATIC_EMPTY yields a 4% decrease in time overhead per call but doubles the space overhead per type. (On msvc 10 the decrease in time overhead is closer to 10%.) Data (Debug): | funcion ptr | function | function (static empty) time/call | 6.33e-09s | 2.62e-08s | 2.26e-08s space/type | 32B | 48B | 64B space/obj | 8B | 32B | 32B Result (Debug): Defining BOOST_FUNCTION_USE_STATIC_EMPTY yields a 18% decrease in time overhead per call but doubles the space overhead per type. So, I think the current boost::function implementation is certainly the right default, since many users would not appreciate doubling the static space overhead for a time savings of less than 10% per call. However, I think it is a good idea to offer users the opertunity to tinker and experiment with this trade-off, so that they can choose what works best for their application. Daniel Walker