verschiedene Funktionen benchmarken



  • Dieser Beitrag wurde gelöscht!


  • ja cool 🙂
    via Destruktor kann man das auch machen. Google Benchmark wäre für meine Quick&Dirty tests doch ein kleiner Overhead, den ich vermeiden möchte. Ich hatte dann noch irgendwie eine Überlegung Richtung Funktionspointer, aber nichts konkretes.

    Habe hier noch eine Lösung:

    #define TEST(X)                                                                                    \
    {                                                                                                  \
           int iter = 1000;                                                                            \
           auto start = high_resolution_clock::now();                                                  \
           for (int i = 0; i < iter; i++)                                                              \
           {                                                                                           \
                X;                                                                                     \
           }                                                                                           \
           auto stop = high_resolution_clock::now();                                                   \
           auto duration = duration_cast<nanoseconds>(stop - start);                                   \
           double time = (double)duration.count() / (double)(iter * 1000);                             \
           std::cout << "time: " << std::fixed << std::setprecision(2) << time << " us" << std::endl;  \
    }
    
    void main()
    {
        TEST(meine_tolle_Funktion_A(123, 234, 345));
        TEST(meine_tolle_Funktion_B(ABC, DEF));
        TEST(meine_tolle_Funktion_C(XYZ));
    }
    

    zugegeben, nicht sehr elegant. ...aber es funktioniert xD
    Außerdem noch parametrierbar 🙂

    euch allen nochmals danke.
    habt ein schönes Wochenende



  • Ich kann dir noch eine C++ Lösung ohne Makros anbieten:

    #include <chrono>
    #include <iomanip>
    #include <iostream>
    #include <string>
    #include <thread>
    
    template<typename Callable, typename ...Params>
    void benchmark( Callable callable, Params&&... p )
    {
       auto const start = std::chrono::high_resolution_clock::now();
       callable( std::forward<Params>( p )... );
       auto const stop = std::chrono::high_resolution_clock::now();
       auto const duration = std::chrono::duration_cast<std::chrono::microseconds>( stop - start );
       std::cout << "time: " << std::fixed << std::setprecision(2) << duration.count() << "µs" << std::endl;
    }
    
    void f()
    {
       std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
    }
    
    void g( unsigned int duration )
    {
       std::this_thread::sleep_for( std::chrono::milliseconds( duration ) );
    }
    
    void h( std::size_t count, std::string const& message )
    {
       for( size_t i = 0; i < count; ++i )
       {
          std::cout << i << ": " << message << "\n";
       }
    }
    
    int main()
    {
       benchmark( f );
       benchmark( g, 20 );
       benchmark( h, 4, "Hello World" );
       return 0;
    }
    


  • Oder leicht angepasst mit lambda syntax

    #include <chrono>
    #include <iomanip>
    #include <iostream>
    #include <string>
    #include <thread>
    #include <functional>
    
    void benchmark(const std::function<void()>& callable_wrapper)
    {
       auto const start = std::chrono::high_resolution_clock::now();
       callable_wrapper();
       auto const stop = std::chrono::high_resolution_clock::now();
       auto const duration = std::chrono::duration_cast<std::chrono::microseconds>( stop - start );
       std::cout << "time: " << std::fixed << std::setprecision(2) << duration.count() << "µs" << std::endl;
    }
    
    void f()
    {
       std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
    }
    
    void g( unsigned int duration )
    {
       std::this_thread::sleep_for( std::chrono::milliseconds( duration ) );
    }
    
    void h( std::size_t count, std::string const& message )
    {
       for( size_t i = 0; i < count; ++i )
       {
          std::cout << i << ": " << message << "\n";
       }
    }
    
    int main()
    {
       benchmark([]{ f(); });
       benchmark([]{ g(20); });
       benchmark([]{ h(4, "Hello World"); });
       return 0;
    }
    

    Bisschen mehr Schreibarbeit, aber dafür der normale funktionsaufruf sichtbar.

    Oder wahlweise:

    benchmark(std::bind(h, 4, "Hello World"));
    

    was auch etwas expliziter ist und mir deswegen besser gefällt (als die Lösung von DocShoe, persönlich würde ich eher lambda als std::bind nutzen)



  • Jau, gefällt mir auch besser 😉



  • vielen Dank 🙂

    wieder was gelernt 😁



  • @Leon0402 sagte in verschiedene Funktionen benchmarken:

    void benchmark(const std::function<void()>& callable_wrapper)
    

    geht das auch irgendwie so?:

    void benchmark(const std::function<int()>& callable_wrapper)
    

    bekomme dann immer diesen Fehler in visual studio 😕

    Fehler C2664 "void benchmark(const std::function<int (void)> &)" : Konvertierung von Argument 1 von "execute2::<lambda_65e5234ff049377ee7d6eeabbe858357>" in "const std::function<int (void)> &" nicht möglich
    


  • @SBond sagte in verschiedene Funktionen benchmarken:

    geht das auch irgendwie so?:
    void benchmark(const std::function<int()>& callable_wrapper)

    bekomme dann immer diesen Fehler in visual studio

    Das sollte gehen. Aber dann musst du deine Lamdas natürlich ändern (z.B. [](int){}) und den Aufruf von callable_wrapper() logischerweise auch durch callable_wrapper(irgendein_int) ändern.

    std::function hat auch overhead im Gegensatz zur getemplateten Funktion. Falls du micro-Benchmarking machst, könnte das u.U. relevant sein, wenn du eine Loop um den callable_wrapper bauen willst.

    PS: warum eigentlich die std::function als const&? Ich würde die normalerweise per value nehmen, aber kommt wahrscheinlich alles immer darauf an 🙂

    PS2: ACH VERDAMMT! ES IST ZU FRÜH FÜR MICH!
    Ich habe statt void benchmark(const std::function<int()>& callable_wrapper) irgendwie void benchmark(const std::function<void(int)>& callable_wrapper) gelesen. Sorry.

    Aber auch void benchmark(const std::function<int()>& callable_wrapper) geht natürlich, dann musst du in deinem Lambda aber einen int oder irgendwas in-int-konvertierbares returnen. Wie sieht denn dein Lambda aus?



  • vielen Dank! ...und ich kam gestern selbst nach vielen Stunden einfach nicht darauf.

    Hier mal der angepasste code von Leon0402:

    #include <chrono>
    #include <iomanip>
    #include <iostream>
    #include <string>
    #include <thread>
    #include <functional>
    
    void benchmark(const std::function<int()>& callable_wrapper)
    {
       int retVal = 0;
       auto const start = std::chrono::high_resolution_clock::now();
       retVal  = callable_wrapper();
       auto const stop = std::chrono::high_resolution_clock::now();
       auto const duration = std::chrono::duration_cast<std::chrono::microseconds>( stop - start );
       std::cout << "time: " << std::fixed << std::setprecision(2) << duration.count() << "µs" << "  retVal:" << retVal << std::endl;
    }
    
    void f()
    {
       std::this_thread::sleep_for( std::chrono::milliseconds( 100 ) );
       return 1;
    }
    
    void g( unsigned int duration )
    {
       std::this_thread::sleep_for( std::chrono::milliseconds( duration ) );
       return 2;
    }
    
    void h( std::size_t count, std::string const& message )
    {
       for( size_t i = 0; i < count; ++i )
       {
          std::cout << i << ": " << message << "\n";
       }
       return 3;
    } 
    
    int main()
    {
       benchmark([]{ return f(); });
       benchmark([]{ return g(20); });
       benchmark([]{ return h(4, "Hello World"); });
       return 0;
    }
    

    ...ist nur noch ein nice to have....
    Wenn man in der benchmark-funktion noch einen Parameter anpassen will geht so etwas auch? Ein beispiel wäre hier benchm_v2(), dass natürlich so nicht geht:

    int test_func(int A, int B)
    {
    	return A + B;
    }
    
    
    void benchm(const std::function<int()>& fkt, std::string testStr)
    {
    	// [...]
    	int retval = fkt();
    	// [...]
    	std::cout << testStr << " --> " << retval << std::endl;
    }
    
    void benchm_v2(const std::function<int()>& fkt, int paramA, int paramB, std::string testStr)
    {
    	// [...]
    	int retval = fkt(paramA+123, paramB);
    	// [...]
    	std::cout << testStr << " --> " << retval << std::endl;
    }
    
    int main(int argc, char* argv[])
    {
    	int myA = 3;
    	int myB = 5;
    	std::string testStr = "A + B";
    
    	benchm([&] {return test_func(myA, myB);}, testStr); // --> geht
    	benchm_v2([&] {return test_func();}, myA, myB, testStr); // --> geht nicht
    
    	return 0;
    }
    

    Bzw gibt es Funktionszeiger, bei der die Parameterliste nicht angegeben werden muss? ...ich kenne von damals noch solche Konstrukte:

    int (*fptr)(int, int) = &test_func;
    fptr(myA, myB);
    

    ..aber da gebe ich ja auch die Parameterliste bereits an. 🤔

    ....erstmal einen Kaffee. 😅



  • @SBond sagte in verschiedene Funktionen benchmarken:

    benchm_v2([&] {return test_func();}, myA, myB, testStr); // --> geht nicht

    Du kannst doch die getemplatete Lösung von @DocShoe ohne std::function dafür verwenden. Was ist denn überhaupt der Sinn deines Lambdas in dem "geht nicht"-Fall?!

    Oder ändere
    void benchm_v2(const std::function<int()>& fkt, int paramA, int paramB, std::string testStr)
    in
    void benchm_v2(const std::function<int(int, int)>& fkt, int paramA, int paramB, std::string testStr)
    und
    benchm_v2([&] {return test_func();}, myA, myB, testStr); // --> geht nicht
    in
    benchm_v2(test_func, myA, myB, testStr); // --> geht



  • ahh..... vielen Dank. Stimmt geht beides 😅
    vielen Dank.

    Wegen dem Lambda.... Das hat im Beispiel keine nähere Bedeutung. Ich bin gerade dabei mich wieder etwas einzuüben.

    Nochmals vielen Dank für die Hilfe 🙂


Anmelden zum Antworten