[function] The cost of boost::function

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@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@function@detail@boost@@YA_NZZ ; boost::detail::function::has_empty_target add esp, 4 test al, al jne SHORT $LN20@main mov edx, DWORD PTR $T109940[esp+60] mov eax, DWORD PTR $T109940[esp+64] mov ecx, OFFSET ?stored_vtable@?1???$assign_to@V?$bind_t@HP6AHH@ZV?$list1@U?$arg@$00@boost@@ @_bi@boost@@@_bi@boost@@@?$function1@HH@boost@@AAEXV?$bind_t@HP6AHH@ZV?$list 1@U?$arg@$00@boost@@@_bi@boost@@@_bi@2@@Z@4U?$basic_vtable1@HH@function@deta il@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@main $LN20@main: mov DWORD PTR _f1$[esp+60], 0 $LN18@main: ; Line 11 lea ecx, DWORD PTR _f1$[esp+60] mov DWORD PTR __$EHRec$[esp+68], 0 call ??R?$function1@HH@boost@@QBEHH@Z ; boost::function1<int,int>::operator() The resulting code for BBBB is: ; Line 15 push 1 call ?g@@YAHH@Z ; g add esp, 4 The resulting code for CCCC is: ; Line 19 push 1 call ?g@@YAHH@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@function@detail@boost@@YA_NZZ ; boost::detail::function::has_empty_target 00DD1160 xor al,al 00DD1162 ret ; ??R?$function1@HH@boost@@QBEHH@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

Hi, ...
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.
… I guess the cost of boost::function (or std::function) is more than justified for its use. It is not intended to be used everywhere, (templates would be prefered where performance matters) but is the only way to abstract what a function is and abstract its type. Unless, you have a better way to achieve the effect, I feel your criticism is rather unfair. Julien

> Unless, you have a better way to achieve the effect, I feel your criticism is > rather unfair. No doubt I had. It was BBBB but you have skipped it. And BTW it was not a criticism. It was just information 1. For people who use boost::function and do not know about the scale of code bloat. 2. For the boost developers in case they would like to change something. Probably the user's guide. -- Michael Kochetkov

On 4/17/12 6:42 AM, Michael Kochetkov wrote:
Unless, you have a better way to achieve the effect, I feel your criticism is rather unfair. No doubt I had. It was BBBB but you have skipped it.
BBBB is not a universal replacement for AAAAA. For example, you can't store BBBB in a class member or change/re-assign another function with the same signature anytime, etc. So.. apples and oranges. Regards, -- Joel de Guzman http://www.boostpro.com http://boost-spirit.com

Michael Kochetkov <michael.kv@gmail.com> writes:
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.
The standard and boost leave the return type of bind (and mem_fn) undefined as the actual implementation of the returned binder can vary, which makes it impossible to use reliably on non C++11 compilers. I think most users are aware of the cost implications that function has and try to pass the result of bind in context where the type can be deduced. Maybe a word of warning wouldn't be too bad, though.
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); }

Michael Kochetkov
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
Actually the whole program has no effect. I'd expect gcc to whipe out at least B and C. Perhaps I expect too much from my compiler. If there's no type deletion I expect it to inline everything out reasonably. For example std::for_each shouldn't be any slower than regular loop. I notice "vtable". I thought I read boost::fuction was impled using function pointers instead of inheritance. I wonder if something changed and why. Chris

On 17.4.2012. 0:04, Michael Kochetkov wrote:
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: <snip> 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.
A bit late but FWIW... ...Boost.Function and its 'bloatware' problems are a regular topic on this list. There have been many proposals but near-zero response from the mantainer(s). I've made a major rewrite that solves most of the problems (lists.boost.org/Archives/boost/2010/10/172593.php) so you can try it out if it helps ;) -- "What Huxley teaches is that in the age of advanced technology, spiritual devastation is more likely to come from an enemy with a smiling face than from one whose countenance exudes suspicion and hate." Neil Postman

A bit late but FWIW... ...Boost.Function and its 'bloatware' problems are a regular topic on this list. There have been many proposals but near-zero response from the mantainer(s). I've made a major rewrite that solves most of the problems (lists.boost.org/Archives/boost/2010/10/172593.php) so you can try it out if it helps ;)
An interesting read … What happened to the variadic templates-enabled version of boost::function ? And why did the thread stop ? Looks like something you could push for a review already ? Or did you lose interest is because of the rather fast adoption of C++11 compilers that ships an std::function ? Julien

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.
A bit late but FWIW... ...Boost.Function and its 'bloatware' problems are a regular topic on this list. There have been many proposals but near-zero response from the mantainer(s). I've made a major rewrite that solves most of the problems (lists.boost.org/Archives/boost/2010/10/172593.php) so you can try it out if it helps ;) Thank you for concern. I believe anyone can propose dozens of improvements of boost critical performance issues. But the main purpose of my investigation was to determine if boost is ready for commercial usage or it is still a kind of a playground. I just cannot afford to watch over every programmer in the company to see if they use boost sensibly. And I do understand people who write boost::function< int (int) > f1 = boost::bind(&g, _1 ); instead of boost::_bi::bind_t<int,int (*)(int),boost::_bi::list1<boost::arg<1> > > f2 = boost::bind(&g, _1 ); because it is convenient or they just find it stupid to memorize the second notation because the life is too short for such things.
So I am stuck with Intel Threading Building Blocks, Flex and so on things because I cannot explain the director why his old Delphi program is much faster and much easier for programmers to deal with than the modern C++ stuff. -- Michael Kochetkov
participants (6)
-
Domagoj Saric
-
Hite, Christopher
-
Joel de Guzman
-
Julien Nitard
-
Michael Kochetkov
-
Philipp Moeller