Boost logo

Boost :

Subject: [boost] [function] The cost of boost::function
From: Michael Kochetkov (michael.kv_at_[hidden])
Date: 2012-04-16 18:04:41


Hello, as far as I subscribed to boost mail list for a reason I have decided
to share an interesting (at least for me) observation of boost::function
facility I have encountered several years ago. The observation is about the
cost of the solution and you probably may be interested if you use boost in
your production.

Let us consider the following code:
#include <boost/bind.hpp>
#include <boost/function.hpp>

inline int g(int i) {
        return ++i;
}

int main() {
        // AAAAA
        boost::function< int (int) > f1 = boost::bind(&g, _1 );
        f1(1);

        // BBBB
        boost::_bi::bind_t<int,int (*)(int),boost::_bi::list1<boost::arg<1>
> > f2 = boost::bind(&g, _1 );
        f2(1);

        // CCCC
        auto f3 = boost::bind(&g, _1 );
        f3(1);
}

I have compiled it with Microsoft (R) 32-bit C/C++ Optimizing Compiler
Version 16.00.40219.01 for 80x86 the following way (maximal optimization):
cl -EHsc -Ox -GL -Ob2 -Oi -Fa -IE:\Work\3dparty\boost_1_48_0 m054.cpp

The resulting code for AAAA is:
; Line 10
        mov eax, OFFSET ?g@@YAHH_at_Z ; g
        mov DWORD PTR $T109940[esp+60], eax
        mov eax, DWORD PTR $T109845[esp+64]
        lea ecx, DWORD PTR $T109940[esp+60]
        push ecx
        mov DWORD PTR $T109940[esp+68], eax
        call ?has_empty_target_at_function@detail_at_boost@@YA_NZZ ;
boost::detail::function::has_empty_target
        add esp, 4
        test al, al
        jne SHORT $LN20_at_main
        mov edx, DWORD PTR $T109940[esp+60]
        mov eax, DWORD PTR $T109940[esp+64]
        mov ecx, OFFSET
?stored_vtable@?1???$assign_to_at_V?$bind_t_at_HP6AHH@ZV?$list1_at_U?$arg@$00_at_boost@@
@_bi_at_boost@@@_bi_at_boost@@@?$function1_at_HH@boost@@AAEXV?$bind_t_at_HP6AHH@ZV?$list
1_at_U?$arg@$00_at_boost@@@_bi_at_boost@@@_bi_at_2@@Z_at_4U?$basic_vtable1_at_HH@function_at_deta
il_at_2@B ; `boost::function1<int,int>::assign_to<boost::_bi::bind_t<int,int
(__cdecl*)(int),boost::_bi::list1<boost::arg<1> > > >'::`2'::stored_vtable
        or ecx, 1
        mov DWORD PTR _f1$[esp+68], edx
        mov DWORD PTR _f1$[esp+72], eax
        mov DWORD PTR _f1$[esp+60], ecx
        jmp SHORT $LN18_at_main
$LN20_at_main:
        mov DWORD PTR _f1$[esp+60], 0
$LN18_at_main:
; Line 11
        lea ecx, DWORD PTR _f1$[esp+60]
        mov DWORD PTR __$EHRec$[esp+68], 0
        call ??R?$function1_at_HH@boost@@QBEHH_at_Z ;
boost::function1<int,int>::operator()

The resulting code for BBBB is:
; Line 15
        push 1
        call ?g@@YAHH_at_Z ; g
        add esp, 4

The resulting code for CCCC is:
; Line 19
        push 1
        call ?g@@YAHH_at_Z ; g
        add esp, 4

I have learned that personally I shall never use boost::function. You
probably may want to investigate such a code bloat. Though it is probably
the known and expected behavior.
And I do agree that CCCC is not quite relevant here. Just for information.

--
Michael Kochetkov
P.S. The traditional full story for AAAA, that includes intermediate calls.
Though it is not really full -- I have given up for three more calls inside
the boost::function1<int,int>::operator() function.
;	// AAAAA
;	boost::function< int (int) > f1 = boost::bind(&g, _1 );
;	f1(1);
002661B9  mov         eax,261170h  
002661BE  mov         dword ptr [esp+4],eax  
002661C2  mov         eax,dword ptr [esp+8]  
002661C6  lea         ecx,[esp+4]  
002661CA  push        ecx  
002661CB  mov         dword ptr [esp+0Ch],eax  
002661CF  call        00261160  
002661D4  add         esp,4  
002661D7  test        al,al  
002661D9  jne         002661F9  
002661DB  mov         edx,dword ptr [esp+4]  
002661DF  mov         eax,dword ptr [esp+8]  
002661E3  mov         ecx,26A028h  
002661E8  or          ecx,1  
002661EB  mov         dword ptr [esp+14h],edx  
002661EF  mov         dword ptr [esp+18h],eax  
002661F3  mov         dword ptr [esp+0Ch],ecx  
002661F7  jmp         00266201  
002661F9  mov         dword ptr [esp+0Ch],0  
00266201  lea         ecx,[esp+0Ch]  
00266205  mov         dword ptr [esp+38h],0  
0026620D  call        002611D0  
; ?has_empty_target_at_function@detail_at_boost@@YA_NZZ ;
boost::detail::function::has_empty_target
00DD1160  xor         al,al  
00DD1162  ret  
; ??R?$function1_at_HH@boost@@QBEHH_at_Z	;
boost::function1<int,int>::operator()
00DD11D0  push        0FFFFFFFFh  
00DD11D2  push        0DD7810h  
00DD11D7  mov         eax,dword ptr fs:[00000000h]  
00DD11DD  push        eax  
00DD11DE  sub         esp,58h  
00DD11E1  push        esi  
00DD11E2  mov         eax,dword ptr ds:[00DDB038h]  
00DD11E7  xor         eax,esp  
00DD11E9  push        eax  
00DD11EA  lea         eax,[esp+60h]  
00DD11EE  mov         dword ptr fs:[00000000h],eax  
00DD11F4  mov         eax,dword ptr [ecx]  
00DD11F6  test        eax,eax  
00DD11F8  jne         00DD1248  
00DD11FA  lea         eax,[esp+0Ch]  
00DD11FE  push        eax  
00DD11FF  lea         ecx,[esp+14h]  
00DD1203  mov         dword ptr [esp+10h],0DDA008h  
00DD120B  call        00DD187F  
00DD1210  mov         dword ptr [esp+10h],0DDA058h  
00DD1218  lea         eax,[esp+10h]  
00DD121C  lea         esi,[esp+1Ch]  
00DD1220  mov         dword ptr [esp+68h],0  
00DD1228  call        00DD1600  
00DD122D  lea         esi,[esp+3Ch]  
00DD1231  mov         byte ptr [esp+68h],1  
00DD1236  call        00DD1640  
00DD123B  push        0DDA7A8h  
00DD1240  mov         ecx,esi  
00DD1242  push        ecx  
00DD1243  call        00DD23CA  
00DD1248  and         eax,0FFFFFFFEh  
00DD124B  mov         edx,dword ptr [eax+4]  
00DD124E  add         ecx,8  
00DD1251  push        1  
00DD1253  push        ecx  
00DD1254  call        edx  
00DD1256  add         esp,8  
00DD1259  mov         ecx,dword ptr [esp+60h]  
00DD125D  mov         dword ptr fs:[0],ecx  
00DD1264  pop         ecx  
00DD1265  pop         esi  
00DD1266  add         esp,64h  
00DD1269  ret  

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk