Binary size when using std::function with lambda expression

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

Binary size when using std::function with lambda expression

shirley breuer via cfe-dev

Hello,


When using std::function instead of function pointer (see the sample of code) on Mac, we get a huge difference between size of generated binary (80ko when using function pointer and 157ko whit std::function).

I use Xcode to build debug with -O0 -std=gnu++14 and libc++.

It doesn't seem to have the same result on windows or linux.

Is it something normal ?


Here's the code sample :


#include <iostream>

#include <functional>



int main(int argc, const char * argv[]) {

    std::function<void()> f = [](){std::cout << "LOG2\n";};

//    void (*f)() = [](){std::cout << "LOG3\n";};

    

    f();

    

    return 0;

}



Thanks,

Cyril

Cyril Makloufi
Développeur
Email : [hidden email]
Web : www.4d.com
4D SAS
66 route de Sartrouville
Parc Les Erables - Batiment 4
78230 Le Pecq - France
Standard : +33 1 30 53 92 00


 


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Binary size when using std::function with lambda expression

shirley breuer via cfe-dev
Hi Cyril,

https://godbolt.org/z/vv3xWP   generated 467 lines of assembler with clang trunk and -O0 (on Linux, I suppose), versus 58 lines for the function pointer.

With -O2 it was 76 lines vs 20 lines.
(Nine lines are always used to initialize iostream and set up its destruction)

There may be extra code linked in from libc++ for std::function.

Csaba


On Fri, 8 Jan 2021 at 11:45, Cyril Makloufi via cfe-dev <[hidden email]> wrote:

Hello,


When using std::function instead of function pointer (see the sample of code) on Mac, we get a huge difference between size of generated binary (80ko when using function pointer and 157ko whit std::function).

I use Xcode to build debug with -O0 -std=gnu++14 and libc++.

It doesn't seem to have the same result on windows or linux.

Is it something normal ?


Here's the code sample :


#include <iostream>

#include <functional>



int main(int argc, const char * argv[]) {

    std::function<void()> f = [](){std::cout << "LOG2\n";};

//    void (*f)() = [](){std::cout << "LOG3\n";};

    

    f();

    

    return 0;

}



Thanks,

Cyril

Cyril Makloufi
Développeur
Email : [hidden email]
Web : www.4d.com
4D SAS
66 route de Sartrouville
Parc Les Erables - Batiment 4
78230 Le Pecq - France
Standard : +33 1 30 53 92 00


 

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


--
You can get very substantial performance improvements
by not doing the right thing. - Scott Meyers, An Effective C++11/14 Sampler
So if you're looking for a completely portable, 100% standards-conformant way
to get the wrong information: this is what you want. - Scott Meyers (C++TDaWYK)

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Binary size when using std::function with lambda expression

shirley breuer via cfe-dev
In reply to this post by shirley breuer via cfe-dev

[hidden email] might be a good place to send this as well, since it’s possible it’s a libc++ thing.

 

From: cfe-dev <[hidden email]> on behalf of cfe-dev <[hidden email]>
Reply-To: Cyril Makloufi <[hidden email]>
Date: Friday, January 8, 2021 at 2:45 AM
To: cfe-dev <[hidden email]>
Subject: [cfe-dev] Binary size when using std::function with lambda expression

 

Hello,

 

When using std::function instead of function pointer (see the sample of code) on Mac, we get a huge difference between size of generated binary (80ko when using function pointer and 157ko whit std::function).

I use Xcode to build debug with -O0 -std=gnu++14 and libc++.

It doesn't seem to have the same result on windows or linux.

Is it something normal ?

 

Here's the code sample :

 

#include <iostream>

#include <functional>

 

 

int main(int argc, const char * argv[]) {

    std::function<void()> f = [](){std::cout << "LOG2\n";};

//    void (*f)() = [](){std::cout << "LOG3\n";};

    

    f();

    

    return 0;

}

 

 

Thanks,

Cyril

Cyril Makloufi

Développeur

 

Email :

[hidden email]

Web :

www.4d.com

4D SAS

66 route de Sartrouville
Parc Les Erables - Batiment 4

78230 Le Pecq - France

 

Standard :

+33 1 30 53 92 00

 

 

 


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Binary size when using std::function with lambda expression

shirley breuer via cfe-dev
In reply to this post by shirley breuer via cfe-dev
On Fri, Jan 8, 2021 at 5:45 AM Cyril Makloufi via cfe-dev <[hidden email]> wrote:

When using std::function instead of function pointer (see the sample of code) on Mac, we get a huge difference between size of generated binary (80ko when using function pointer and 157ko whit std::function).

This is expected. std::function<void()> is a library type. It does "type erasure," a C++ technique which you can learn about here:
https://www.youtube.com/watch?v=tbUCHifyT24 ("Back to Basics: Type Erasure", CppCon 2019)
Contrast with core-language lambda expressions:
https://www.youtube.com/watch?v=3jCOwajNch0 ("Back to Basics: Lambdas from Scratch", CppCon 2019)

You can do a lot of things with `std::function<void()> f` that you can't do with `void (*f)()`; for example, `std::function<void()> f` can hold a copy of a lambda which itself has captures.

    int i = 42;
    std::function<void()> f = [&]() { std::cout << i; };  // OK
    void (*g)() = [&]() { std::cout << i; };  // Ill-formed

You pay for this flexibility in code size (and speed) (and, in many cases, heap-allocations).

Additionally, std::function is notoriously inefficient even as type-erased types go. This is partly because the paper standard requires it to do so much (e.g. the .target_type() method); and partly because its implementation was done ~15 years ago and maybe we'd like to apply some lessons learned since then, but that would break ABI.

HTH,
Arthur

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev