Funktionslaufzeit "von außen" messen



  • Moin zusammen!

    Hier mal eine Aufgabe aus der Uni - unser Prof ist leider nicht so gut zu erreichen, vielleicht hat ja jemand eine Idee.

    Aufgabe 11001: Performance-Timer

    Bei dieser Aufgabe soll eine Klasse namens PerformanceTimer entwickelt werden, die die Laufzeit einer Funktion misst und auf der Konsole ausgibt.

    Testprogramm:

    #include <iostream>
    #include <string>
    using namespace std;
    
    #include "PerformanceTimer.hpp"
    
    void rechne()
    {
    	PERFORMANCE_TIMER
    	cout << "Bitte Enter druecken: ";	// Hinweis: Wir simulieren hier den Zeitverbrauch
    	string a;				// einer Berechnung durch das Warten auf ENTER
    	getline(cin, a);
    }
    
    int main()
    {
    	rechne();
    	system("pause");
    	return 0;
    }
    

    Hinweise:

    • Die Funktionen rechne() und main() sollen unverändert bleiben.
    • Über den Header ctime erreichen Sie die Funktion clock(), die Ihnen die Millisekunden seit Programmstart zurückgibt.
    • Das Makro __FUNCTION __ liefert den Namen der aktuellen Funktion

    Konsolenausgabe:

    Start von: rechne
    Bitte Enter drücken:
    Ausfuehrungszeit von rechne: 3.06 s
    

    Ich verstehe, dass ich in der zu erstellenden Headerdatei jetzt ein #define-Makro für PERFORMANCE_TIMER erstellen muss und den Funktionsnamen bekomme ich auch, nur wie erfahre ich, wann die "Berechnung" beendet ist? Ich wollte zuerst a == "" überprüfen, aber darauf habe ich ja gar keinen Zugriff...

    Hier meine Headerdatei:

    // PerformanceTimer.hpp
    
    #include <ctime>
    #define PERFORMANCE_TIMER stoppeZeit();
    
    void stoppeZeit()
    {
    	cout << "Start von: " << __FUNCTION__ << endl;
    	auto t0 = clock()
    
    	while (a == "")
    	{
    		// Warten
    	}
    
    	double t = (clock() - t0) / 1000;
    	cout << " Ausfuehrungszeit von " << __FUNCTION__ << ": " << t/1000 << " s";
    }
    

    Ich komme nur einfach nicht drauf, wie man überprüfen kann, ob die Methode noch läuft.
    Hat von euch jemand einen Tipp?

    LG
    Kai


  • Mod

    Mach keine Funktion, sondern ein Klassenobjekt. In seinem Konstruktor setzt es die Startzeit, in seinem Destruktor misst es die Endzeit und macht die Ausgabe.

    PS: Hast du dir deine Ausgabe angesehen? Passt der Name der Funktion, den du erwartest?



  • Du brauchst eine Klasse, die in ihrem Konstruktor den Namen einer Funktion übernimmt. Außerdem muss sich ein Objekt dieser Klasse den Zeitpunkt seiner Erstellung merken. Im Destruktor muss sie dann die vergangene Zeit bestimmen und ausgeben. Das Makro PERFORMANCE_TIMER muss dann ein Objekt dieser Klasse mit dem passenden Parameter erzeugt werden.

    Edit:
    Beaten by SeppJ



  • Und ich kann in der Headerdatei inline Klassen erstellen und Objekte erzeugen? Ich dachte, nur Methoden könnten inline sein, nicht aber ganze Klassen. Ich probiere mal etwas rum, danke euch!



  • @Kai-Brenke
    Der Trick ist mit dem Makro ein Objekt zu erzeugen



  • Du macht eine normale Timer-Klasse, von der du per Macro ein Objekt erzeugst.

    Die Timer-Klasse könnte so oder ähnlich aussehen (ungetestet):

    struct Timer{
      Timer(const char *name) :
        name(name),
        start(std::chrono::high_resolution_clock::now())
      {}
     ~Timer() {
        cout << name << ": " 
          << std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - start).count()
          << "us\n";
      }
      const char *name; // ggf. auch std::string nehmen
      std::chrono::time_point<std::chrono::high_resolution_clock> start;
    };
    

    Du machst dann einfach, dass dein Macro aus void foo(){PERFORMANCE_TIMER cin.get()} sowas wie void foo(){Timer name_des_timers("name des Timers"); cin.get()} macht. Du musst nur noch zusehen, dass dein Variablenname irgendwie eindeutig ist und nicht anderweitig vorkommt (wie macht man das?).



  • Danke! Ich habe schonmal eine funktionierende Lösung:

    // PerformanceTimer.hpp
    
    #include <ctime>
    #include <string>
    #define PERFORMANCE_TIMER Stoppuhr s(__FUNCTION__);
    
    struct Stoppuhr {
    	string funcname;
    	double t0;
    
    	Stoppuhr(const string& function) :
    		funcname(function)
    	{
    		cout << "Start von: " << funcname << endl;
    		t0 = clock();
    	}
    
    	~Stoppuhr()
    	{
    		double t = (clock() - t0) / 1000;
    		cout << " Ausfuehrungszeit von " << funcname << ": " << t << " s";
    	}
    };
    

    Das Argument von @wob stimmt allerdings, man muss natürlich sicherstellen, dass kein anderes Objekt meiner Klasse mit dem gleichen Namen erzeugt wird/wurde - ich schätze, so weit sind wir allerdings noch nicht.



  • @wob sagte in Funktionslaufzeit "von außen" messen:

    Du machst dann einfach, dass dein Macro aus void foo(){PERFORMANCE_TIMER cin.get()} sowas wie void foo(){Timer name_des_timers("name des Timers"); cin.get()} macht. Du musst nur noch zusehen, dass dein Variablenname irgendwie eindeutig ist und nicht anderweitig vorkommt (wie macht man das?).

    Das ist wirklich nicht so einfach, zumindest wenn der Compiler __COUNTER__ nicht unterstützt. Ich werf mal

    void func()
    {
       PERFORMANCE_TIMER;PERFORMANCE_TIMER;
    }
    

    in den Raum.



  • @Kai-Brenke sagte in Funktionslaufzeit "von außen" messen:

    Das Argument von @wob stimmt allerdings, man muss natürlich sicherstellen, dass kein anderes Objekt meiner Klasse mit dem gleichen Namen erzeugt wird/wurde - ich schätze, so weit sind wir allerdings noch nicht.

    Fürs erste hilft es wahrscheinlich, die Stoppuhr nicht "s" zu nennen, das konflikted zu leicht. Wie wäre es mit "private_stoppuhr_fuer##FUNCTION" - oder schau mal FB_ANONYMOUS_VARIABLE in https://github.com/facebook/folly/blob/master/folly/Preprocessor.h an, wenn du was mit counter und Zeile willst.


Anmelden zum Antworten