[gelöst] std::function Overhead?



  • Hi zusammen,

    ich spiele gerade ein wenig mit std::function rum und frage mich, ob man den Overhead etwas reduzieren kann (vllt. durch einen Ersatz?):

    #include <functional>
    
    double foo( double x, double y )
    {
       return x + y;
    }
    
    int main()
    {
       double (*f1)( double, double ) = &foo;
       std::function<double( double, double )> f2 = &foo;
    
       std::size_t const loop_count = 100000000;
    
       double r1 = 0;
       for( std::size_t i = 0; i < loop_count ; ++i )
       {
          r1 += f1( 3, 4 );
       }
    
       double r2 = 0;
       for( std::size_t i = 0; i < loop_count ; ++i )
       {
          r2 += f2( 3, 4 );
       }
    }
    

    Die Schleife mit std::function ist etwa 4-5x langsamer als die mit dem direkten Zeiger. Die absoluten Zahlen sind da total belanglos (2.6ns gegenüber 0.6ns), aber ich frage mich trotzdem, ob man den Faktor iwie kleiner bekommt, vielleicht durch einen (eingeschränkten) Ersatz? Hab noch nicht groß im Netz gesucht, bin dabei aber auf einige Treffer gestossen, die mir relativ groß erscheinen ( Impossibly fast delegates und TransientFunction, wobei TransientFunction wohl einige Einschränkungen hat).
    Ich suche einen schnellen Wrapper, der sowohl freie Funktionen als auch Member Funktionen kapseln kann.

    Edit:
    Hab mal etwas mit verschiedenen Compilern auf wandbox.org rumgespielt, es sieht so aus, als hätte ich da eine miese STL Implementation. Mit dem gcc ab 8.x sind beide Varianten in etwa gleich schnell, nur beim clang gibt es Unterschiede ( grob um den Faktor 2).



  • Bist du sicher dass der Funktionszeiger nicht komplett wegoptimiert wurde?
    Probier's mal so

    double foo( double x, double y )
    {
       return x + y;
    }
    
    typedef double Fun(double, double);
    
    Fun* getFunPtr() {
        Fun* volatile dummy = &foo;
        return dummy;
    }
    
    
    int main()
    {
       double (*f1)( double, double ) = getFunPtr();
       std::function<double( double, double )> f2 = getFunPtr();
    


  • @DocShoe sagte in std::function Overhead?:

    Edit:
    Hab mal etwas mit verschiedenen Compilern auf wandbox.org rumgespielt, es sieht so aus, als hätte ich da eine miese STL Implementation. Mit dem gcc ab 8.x sind beide Varianten in etwa gleich schnell, nur beim clang gibt es Unterschiede ( grob um den Faktor 2).

    Hm. Riecht für mich jetzt auch eher danach als ob da Dinge wegoptimiert werden, die in realen Programmen dann doch nicht wegoptimiert werden können.

    Speziell wenn du nen std::function mit einem Funktionszeiger befüllst, dann muss das eigentlich langsamer sein als ein direkter Aufruf über den selben Funktionszeiger.



  • Das war ein guter Hinweis, danke. Mit deinem Ansatz ist std::function nur noch 25% langsamer als der Aufruf per pointer-to-function. Das kann ich rechtfertigen 😉



  • @hustbaer sagte in std::function Overhead?:

    Speziell wenn du nen std::function mit einem Funktionszeiger befüllst, dann muss das eigentlich langsamer sein als ein direkter Aufruf über den selben Funktionszeiger.

    Dass das nicht umsonst ist war mir klar. Fand halt nur den Faktor 4x+ erschreckend hoch. Und, wie gesagt, absolut waren das bei dem Testlauf 2.6ns pro Aufruf per std::function, inkl. Funktionsrumpf.


Anmelden zum Antworten