Zeitmessung std::chrono


  • Mod

    hustbaer schrieb:

    Speicherbandbreite, geteilte Rechenwerke, Spinlocks und die 1000 anderen Sachen an die ich jetzt nicht denke.
    Das kann einiges ausmachen.

    Meiner Erfahrung nach absolut vernachlässigbar. Aber:

    hustbaer schrieb:

    Aber die Echtzeit zu messen anstatt der CPU-Zeit gibt dir einen Fehlerfaktor von 1/CPU-Last, was dann eben sehr leicht sehr groß werden kann.

    Hö?
    Wenn mein Programm nur einen Fred verwendet kann ich mit quasi jeder beliebigen Clock messen und werde korrekte Ergebnisse bekommen. Und wenn es mehrere Freds verwendet ist auch oft interessant wie viel Zeit auf der Uhr an der Wand vergangen ist -- man muss dann halt wissen was man messen will und was man gemessen hat.

    Was hat das mit Threads zu tun? Wenn dein Programm nur 50% CPU-Last bekommt, weil gleichzeitig ein anderes Programm mit gleicher Priorität läuft, dann misst du eine doppelt so große Echtzeit wie das Programm eigentlich bräuchte.
    Und ja, wenn dein Programm parallelisiert ist, dann ist Echtzeit vermutlich auch nicht das was du wissen möchtest, schließlich will man ja allgemeine wissen, wie viel CPU-Leistung ein Programm verbraucht hat, damit man einschätzen kann, wie viel Echtzeit es auf einem anderen System braucht.



  • hustbaer schrieb:

    MSVC 11 RC verwendet z.B. für alle std:: Clocks die Systemzeit (was total bekloppt ist weil es unter Windows für steady_clock den Tick-Count gäbe und für high_resolution_clock QueryPerformanceCounter ).
    Und die Systemzeit unter Windows hat ne Auflösung von irgendwo zwischen 1 und 15ms.

    Nachdem hustbaer das geschrieben hatte, hab ich mir mal QueryPerformanceCounter angeschaut, herausgekommen ist das:

    namespace resolution
    {
    	static const double ns = 1000000000.0;
    	static const double us = 1000000.0;
    	static const double ms = 1000.0;
    	static const double s  = 1.0;
    }
    class stopwatch
    {
    	private:
    		double res;
    		double pc_freq;
    		__int64 start_time;
    		__int64 stop_time;
    	public:
    		stopwatch(double r = resolution::ms) : res(r), pc_freq(0.0), start_time(0), stop_time(0) {}
    
    		void start()
    		{
    			LARGE_INTEGER li;
    			if( !QueryPerformanceFrequency(&li) )
    				cerr << "QueryPerformanceFrequency Not Available";
    
    			pc_freq = double(li.QuadPart)/res;
    
    			QueryPerformanceCounter(&li);
    			start_time = li.QuadPart;
    		}
    
    		void stop()
    		{
    			LARGE_INTEGER li;
    			QueryPerformanceCounter(&li);
    			stop_time = li.QuadPart;
    		}
    
    		double elapsed()
    		{
    			return (stop_time-start_time)/pc_freq;
    		}
    };
    
    int main()
    {
    	stopwatch timer(resolution::us);
    	timer.start();
    	vector<int> v(2000,1);
    	timer.stop();
    
    	cout << endl << timer.elapsed() << " us"; // ~22.58 us
    }
    

    Mit dieser Genauigkeit kann ich gut Leben.

    SeppJ schrieb:

    Was hat das mit Threads zu tun? Wenn dein Programm nur 50% CPU-Last bekommt, weil gleichzeitig ein anderes Programm mit gleicher Priorität läuft, dann misst du eine doppelt so große Echtzeit wie das Programm eigentlich bräuchte.

    Das Problem habe ich bei QueryPerformanceCounter wohl immer noch. Aber da ich nun im us-Bereich messen kann, bin ich erstmal zufrieden.

    Falls einer einen Fehler in der Stopwatch Klasse findet, bitte melden.

    Danke euch.


  • Mod

    Zeitmessung schrieb:

    SeppJ schrieb:

    Was hat das mit Threads zu tun? Wenn dein Programm nur 50% CPU-Last bekommt, weil gleichzeitig ein anderes Programm mit gleicher Priorität läuft, dann misst du eine doppelt so große Echtzeit wie das Programm eigentlich bräuchte.

    Das Problem habe ich bei QueryPerformanceCounter wohl immer noch.

    Nein, hast du nicht. Ist dir nicht klar, was CPU-Zeit ist und was im Vergleich dazu deine Armbanduhr anzeigt?

    Was hast du überhaupt vor?



  • SeppJ schrieb:

    Nein, hast du nicht. Ist dir nicht klar, was CPU-Zeit ist und was im Vergleich dazu deine Armbanduhr anzeigt?

    Hmm, ich dachte die CPU-Zeit bezieht sich auf alle Cores?

    SeppJ schrieb:

    Was hast du überhaupt vor?

    Ich habe insgesamt 1000 std::pair . Ein pair besteht aus einem Namen (std::string) und einem Wert (int). Ein STLContainer soll sich um die Paare kümmern. Der Name dient der Identifikation. Ich kenne alle Namen und mich interessieren die daszugehörigen Werte.

    Nehme ich std::vector so brauch ich für jeden Zugriff auf ein Element std::find_if . Nun will ich messen, wie viel Zeit es mich kostet, wenn ich auf 1, 2, 3, 4, 5... Paare nacheinander zugreife.

    Nehme ich std::map , so ist der Key der Name und der Value der Wert. Für einen Zugriff brauche ich nur noch den operator[]. Ich will jetzt auch hier messen, wie viel Zeit es mich kostet, wenn ich auf 1, 2, 3, 4, 5... Paare nacheinander zugreife.



  • SeppJ schrieb:

    Zeitmessung schrieb:

    SeppJ schrieb:

    Was hat das mit Threads zu tun? Wenn dein Programm nur 50% CPU-Last bekommt, weil gleichzeitig ein anderes Programm mit gleicher Priorität läuft, dann misst du eine doppelt so große Echtzeit wie das Programm eigentlich bräuchte.

    Das Problem habe ich bei QueryPerformanceCounter wohl immer noch.

    Nein, hast du nicht. Ist dir nicht klar, was CPU-Zeit ist und was im Vergleich dazu deine Armbanduhr anzeigt?

    Doch, hat er schon.
    QueryPerformanceCounter misst zwar CPU-Zeit, ist aber nicht Thread- bzw. Prozess-affin.

    Und das von dir erwähnte Problem vermeidet man einfach indem man sein System nicht sonderlich stesst, die Prozesspriorität raufschraubt und den besten Wert von mehreren Messungen nimmt.

    Die prozessabhängige CPU Zeit ist unter Windows nach meiner Erfahrung recht ungenau, daher verwende ich die nie.

    SeppJ schrieb:

    Und ja, wenn dein Programm parallelisiert ist, dann ist Echtzeit vermutlich auch nicht das was du wissen möchtest, schließlich will man ja allgemeine wissen, wie viel CPU-Leistung ein Programm verbraucht hat, damit man einschätzen kann, wie viel Echtzeit es auf einem anderen System braucht.

    Och Sepp, ich weiss schon selber was mich interessiert. Und oft genug interessiert mich bloss die Echtzeit die vergeht.

    Klar, manchmal auch die Zeit die man in Summe auf allen Cores verbraten hat.
    Allerdings kann man die Werte kaum brauchen, da man erfahrungsgeämss nicht sinnvoll hochrechnen kann.
    Also die Rechnung "eine Instanz meiner Anwendung braucht für ein Work-Item 1 Sekunde und verbrät dabei 33% der gesamt verfügbaren CPU Leistung, also kann ich mit 3 Instanzen parallel 3 Work-Items pro Sekunde abarbeiten" geht einfach nicht auf. Wie gesagt Erfahrungswert, woran genau das liegt kann ich dir jetzt auch nicht sagen.

    Deswegen sag ich ja: man muss halt einfach wissen was man wissen will und dann das richtige messen.


  • Mod

    Nimm um Himmelswillen einen Profiler für Performancemessungen! Besonders, wenn du dich selber so schwer mit der Zeitmessung tust.

    Zeitmessung schrieb:

    Hmm, ich dachte die CPU-Zeit bezieht sich auf alle Cores?

    Nutz doch einfach mal Google, wenn du nicht weißt, was ein Fachbegriff bedeutet.

    hustbaer schrieb:

    Doch, hat er schon.
    QueryPerformanceCounter misst zwar CPU-Zeit, ist aber nicht Thread- bzw. Prozess-affin.

    Ach, Windows 🙄 . Kenne mich da nicht so aus. Gibt es da nichts, was die Threads zusammenzählt? Linux kann das :p .

    hustbaer schrieb:

    Und das von dir erwähnte Problem vermeidet man einfach indem man sein System nicht sonderlich stesst, die Prozesspriorität raufschraubt und den besten Wert von mehreren Messungen nimmt.

    Wenn aber andere Leute auf dem Rechner rechnen? Ach, irgendwie programmier ich in einer anderen Welt als der Windwosdesktopentwickler…



  • @Zeitmessung
    Nur um das nochmal klarzustellen: QueryPerformanceCounter misst die Zeit, genau so wie sie auf der Uhr an der Wand runtertickt.
    Eine Messung einer "mittleren" Dauer sollte mit QueryPerformanceCounter und z.B. der Systemzeit inetwa den selben Wert ergeben (vorausgesetzt die Systemzeit wurde nicht während der Messung verstellt natürlich).

    Wie viele Cores/Threads/Prozesse/... das System hat und was die alle machen oder nicht machen ist dabei vollkommen egal.

    QueryPerformanceCounter verglichen mit der Systemzeit:
    * Kein definierter "Nullpunkt", d.h. man kann auch nicht von einem QueryPerformanceCounter -Wert auf ein Datum+Zeit hochrechnen
    * Schlechtere absolute Genauigkeit (so genau wie der verwendete Hardware-Timer, kann also nicht mit einem Timer mithalten der immer wieder mit externen Quellen wie Time-Servern abgeglichen wird)
    * Nicht brauchbar um Messungen über Standby/Hinerbation/... hinweg zu machen
    * Viel bessere Auflösung



  • SeppJ schrieb:

    hustbaer schrieb:

    Doch, hat er schon.
    QueryPerformanceCounter misst zwar CPU-Zeit, ist aber nicht Thread- bzw. Prozess-affin.

    Ach, Windows 🙄 . Kenne mich da nicht so aus. Gibt es da nichts, was die Threads zusammenzählt? Linux kann das :p .

    Windows kann das auch. Kann man ja sogar im Task-Manager als Spalte dazuklicken.
    Wie die Funktion heisst müsste ich selbst nochmal nachgoogeln, ist mir den Aufwand jetzt grad nicht wert.
    Aber wie gesagt: die Werte die du da rausbekommst sind nicht für Hochrechnungen geeignet.
    (Es sei denn es hätte sich da seit Windows 2000 was getan - mit neueren Windosen hab ich das nichtmehr probiert)

    hustbaer schrieb:

    Und das von dir erwähnte Problem vermeidet man einfach indem man sein System nicht sonderlich stesst, die Prozesspriorität raufschraubt und den besten Wert von mehreren Messungen nimmt.

    Wenn aber andere Leute auf dem Rechner rechnen? Ach, irgendwie programmier ich in einer anderen Welt als der Windwosdesktopentwickler…

    Wenn andere Leute auf dem Rechner rechnen hat man Pech 🙂
    Ne, is schon klar, in solchen Situationen ist alles etwas anders. Da geht's mir aber genau so wie dir bei Windows 🙂



  • clock::ratio ist ja statisch, und da die erreichbare Genauigkeit oft erst zur Laufzeit bekannt ist kann es schonmal nicht genau stimmen.

    Statisch bedeutet nicht, dass sie zur Kompilezeit bekannt sein muss. Der Wert kann auch bei Initialisierung der Runtime gesetzt werden. Ausserdem werden die Laufzeitbibliotheken meist fuer ein System gebaut, so dass der verwendete Timer zur Kompilezeit ebenfalls bekannt ist.



  • knivil schrieb:

    clock::ratio ist ja statisch, und da die erreichbare Genauigkeit oft erst zur Laufzeit bekannt ist kann es schonmal nicht genau stimmen.

    Statisch bedeutet nicht, dass sie zur Kompilezeit bekannt sein muss. Der Wert kann auch bei Initialisierung der Runtime gesetzt werden.

    Statisch im Sinne von compile-time-constant.
    Guckst du http://www.cplusplus.com/reference/std/ratio/ratio/
    Also nix mit Runtime.

    Ausserdem werden die Laufzeitbibliotheken meist fuer ein System gebaut, so dass der verwendete Timer zur Kompilezeit ebenfalls bekannt ist.

    Weil jedes "System" immer nur genau eine Hardware unterstützt oder wie?
    Nene, welche Timer wirklich verfügbar sind wissen Desktop-OS' erst beim hochfahren. Die C++ Implementierung setzt dann einfach einen Wert ein der ausgehend von der bestmöglichen Auflösung nicht allzuviel verschenkt. Wobei "bestmögliche Auflösung" auch durchaus die Auflösung der OS-API sein kann, und ganz ganz weit weg von der effektiven Auflösung der besten aktuellen Implementierung.


Anmelden zum Antworten