Hohe CPU-Last wegen clock_gettime



  • Hallo

    Ich habe eine Vector den ich ständig durchlaufe und ich muss pro Vector-Element messen wieviel Zeit ich für die Abarbeitung benötigt habe.
    Der Vector hat eine Größe von 10000 Elementen

    for(std::vector<Data>::iterator it=vec.begin(); it != vec.end(); ++it)
    {
        clock_gettime(CLOCK_MONOTONIC, &tp1);
    
        .... irgend einen code ausführen ....
    
        clock_gettime(CLOCK_MONOTONIC, &tp2);
        it->dauer = diff(t2, t1);
    }
    

    Leider erzeugt clock_gettime(CLOCK_MONOTONIC, &tp1); eine sehr hohe CPU-Last und meine CPU-Last verdoppelt sich von 8% (ohne clock_gettime) auf 15%

    Ist das normal oder gibt es eine Art Stoppuhr die weniger CPU benötigt?



  • Warum misst du nicht die Zeit aller und mittelst ueber die Anzahl? D.h. du hast nur zwei clock_gettime-Aufrufe.



  • Ich brauche keinen Durchschnittswert, sondern leider den genauen wert pro Abarbeitung --> Große Schwankungen bei der Abarbeitung eines Elementes.



  • Du kannst beipsielsweise ein get_clocktime einsparen, da das letzte get_clocktime in der Schleife sich nicht grossartig von dem unterscheidet, was am Anfang in der Schleife steht. Pseudocode:

    last_time = ...
    current_time = get_time()
    for( ....)
    {
       last_time = current_time;
    
       // do something
    
       current_time = get_time();
       diff  = current - last;
    }
    


  • Danke.
    Leider ist die hohe CPU-Last zwar verringert worden, aber trotzdem ist die CPU-Last um 50% mehr als ohne dem Befehl.
    Es kann auch sein, dass ich statt. 10.000 Elementen 200.000 Elemente im Vector habe und dann ist der Zuwachs der CPU-LAST wegen clock_gettime enorm.

    Gibt es eine andere Möglichkeit bzgl. einer Stoppuhr mit weniger CPU-Last?
    Mir reichen zwei Nachkommerstellern aus (also hundertstel), jedoch kann ich nicht die realtime verwenden da nicht ausgeschlossen ist, dass die Zeit umgestellt wird (ob mit NTP oder manuell).


  • Mod

    Wenn dein Code so gut wie nichts macht, dann machen zwei weitere Funktionsaufrufe eben ziemlich viel aus. Da ändert auch die Benutzung einer anderen Uhr nichts dran, das liegt einfach an deinem Vorhaben. Die Frage ist natürlich, wieso du dieses recht ungewöhnliche Vorhaben überhaupt hast. Erklär doch mal.



  • Nun, manchmal ist es eben wichtig, auch die Varianz zu kennen (eigentlich immer, denn Mittelwerte bspw. bei Latenz/Reaktionszeit/Deadlines sind ohne Bedeutung wenn Abweichungen/min/max unbekannt sind). Mache ich aehnlich, wenn Arbeitspakete unterschiedlich gross sein koennen.

    Ansonsten: Wenn du die Zeit pro Element messen musst, dann musst du sie messen. Weniger geht nicht.

    reichen zwei Nachkommerstellern aus (also hundertstel)

    Die Einheit ist interessant: Zwei Nachkommastellen von Tagen, Stunden, Minuten, ... ?

    jedoch kann ich nicht die realtime verwenden da nicht ausgeschlossen ist, dass die Zeit umgestellt wird

    So lange braucht die Bearbeitung eines Arbeitspaketes? Weiterhin: Diese Aussreisser sollten relativ einfach durch Statistik zu ermitteln sein.



  • SeppJ schrieb:

    Wenn dein Code so gut wie nichts macht, dann machen zwei weitere Funktionsaufrufe eben ziemlich viel aus. Da ändert auch die Benutzung einer anderen Uhr nichts dran, das liegt einfach an deinem Vorhaben. Die Frage ist natürlich, wieso du dieses recht ungewöhnliche Vorhaben überhaupt hast. Erklär doch mal.

    Naja so würde ich das nicht sagen, das mein code nichts macht. dazwischen sind 100 weitere Methodenaufrufe (ok, das sagt auch nichts aus 🙂 )inkl. div. Stringoperationen und und und
    Das Vorhaben wird dadurch begründet, dass ich zusätzlich zum Aufzeichnen des Wertes auch noch damit ein Timeout realisieren möchte/wollte (Braucht ein Element mehr als Wert X, dann wird dieser übersprungen und der nächste kommt drann)

    knivil schrieb:

    Ansonsten: Wenn du die Zeit pro Element messen musst, dann musst du sie messen. Weniger geht nicht.

    Ev. habe ich den falschen Zugang zu dem Ganzen.
    Der einmalige Aufruf (also Start der "Stoppuhr") kostet schon viel CPU und da ich aber wie oben beschrieben auch eine Zwischenzeit für ein mögliches Timeout benötige wird die CPU-Last ja immer mehr durch clock_gettime.
    Wenn es echt sein muss, dann kann ich wohl irgendwie ohne dem ermittelten Differenzwert leben, aber ohne Timeout kann ich nicht leben.
    Nur kann ich in diesem Fall ein Timeout überhaupt irgendwie realisieren, wenn ich clock_gettime nicht verwenden kann/darf (Timeout wäre zb. 0,5sec) ?

    knivil schrieb:

    Die Einheit ist interessant: Zwei Nachkommastellen von Tagen, Stunden, Minuten, ... ?

    Sorry, die Einheit ist Sekunden.



  • Timeout

    Also ist das eigentliche Problem was ganz anderes, wie SeppJ vermutete. Seupfz. Du willst keine Stoppuhr.



  • aha?
    Ich brauche beides und ich habe auch gesagt, dass ich wenn es echt sein muss auf das andere irgendwie verzichten kann (wenns keine andere Lösung gibt)

    Aber wie wäre dann die CPU schonende Timeout-Lösung?



  • Unter Windows gibt es GetTickCount, was quasi kostenlos ist aber dafür nur 16 ms-Auflösung bietet. Sollte aber für einen solchen Timeout normalerweise ausreichen.

    Unter Linux/Mac ist mir leider nichts vergleichbares bekannt, kannst du aber emulieren, indem du einen separaten Thread laufen lässt, der alle X ms aufwacht und einen globalen Counter aktualisiert (nichts anderes wird unter der Haube unter Windows ablaufen, denn ich sehe keinen anderen Weg, wie GetTickCount in <=20 CPU-Ticks laufen kann).



  • Ich habe mal ein wenig rum experimentiert und kann das Problem nicht nachvollziehen. Bei meinen Tests erzeugt clock_gettime keine wesentliche Last. Und es würde mich eigentlich auch wundern. Die Last ist überhaupt erst messbar, wenn das "do something" fast keine Zeit benötigt.



  • Unter Linux gibts noch CLOCK_MONOTONIC_COARSE. Die Manpage beschreibt das folgendermaßen:

    clock_getres(2) schrieb:

    A faster but less precise version of CLOCK_MONOTONIC. Use when you need very fast, but not fine-grained timestamps.

    Probier's mal aus. Ist halt Linux-only.



  • tntnet schrieb:

    Ich habe mal ein wenig rum experimentiert und kann das Problem nicht nachvollziehen. Bei meinen Tests erzeugt clock_gettime keine wesentliche Last. Und es würde mich eigentlich auch wundern. Die Last ist überhaupt erst messbar, wenn das "do something" fast keine Zeit benötigt.

    Eigentlich wäre schon eine Last vorhanden, da der messbereich auch mal 1sec sein kann.

    appropriate privilege schrieb:

    Unter Linux gibts noch CLOCK_MONOTONIC_COARSE. Die Manpage beschreibt das folgendermaßen:

    clock_getres(2) schrieb:

    A faster but less precise version of CLOCK_MONOTONIC. Use when you need very fast, but not fine-grained timestamps.

    Probier's mal aus. Ist halt Linux-only.

    Das ist ein interessanter Hinweis!

    Ich habe getestet und leider sind die Auswirkungen nicht so wie bei vielen beschrieben (die mittels CLOCK_MONOTONIC_COARSE fast 50% schneller sind)
    Hier ist ein test von einem der ist um weit mehr als 50% schneller
    http://poordeveloper.wordpress.com/tag/clock_gettime/

    hier wird auch darüber diskutiert
    http://stackoverflow.com/questions/6498972/faster-equivalent-of-gettimeofday
    und einer gibt sogar bei einem test an, dass er nur noch 30% der zeit braucht gegenüber dem "einfachen" CLOCK_MONOTONIC

    Ich habe mir folgenden Test runtergeladen https://github.com/dterei/Scraps/tree/master/c/time

    Mein Ergebnis ist:
    - time (s) => 302ns
    - ftime (ms) => 448ns
    - gettimeofday (us) => 401ns
    - clock_gettime (ns) => 386ns (CLOCK_REALTIME)
    - clock_gettime (ns) => 338ns (CLOCK_REALTIME_COARSE)
    - clock_gettime (ns) => 390ns (CLOCK_MONOTONIC)
    - clock_gettime (ns) => 344ns (CLOCK_MONOTONIC_COARSE)

    😮
    Habe ich ein grundlegendes Problem oder warum sind meine Werte so extrem schlecht?
    Kann bitte wer auf einem Linux-System auch die Tests durchführen https://github.com/dterei/Scraps/tree/master/c/time
    DANKE!!!!



  • Ich bekomme diese Ausgabe:
    `./time

    time per call: 3 nanoseconds

    ./ftime

    time per call: 31 nanoseconds

    ./gettimeofday

    time per call: 27 nanoseconds

    ./clock_gettime

    time per call: 6 nanoseconds

    ./cached_time

    time per call: 0 nanoseconds

    (total) c2 = 1118589389 (n = 500000000)`

    Kann allerdings aus frühereren Tests deine Werte bestätigen (da hatte ich eher bis zu 2000-4000 CPU-Zyklen pro Call). Die niedrigen Werte irritieren mich gerade ein wenig - keine Ahnung, ob das in neueren Linux-Versionen effizienter geworden ist, oder ob es am 32->64 bit-Wechsel liegt, ob die Calls weniger kosten, wenn man sie oft hintereinander in einer Schleife aufruft (anzunehmen wäre das) oder ob ein anderer Grund vorliegt.



  • Ach, schau an. Hier mit -m32:

    `./time

    time per call: 76 nanoseconds

    ./ftime

    time per call: 95 nanoseconds

    ./gettimeofday

    time per call: 79 nanoseconds

    ./clock_gettime

    time per call: 88 nanoseconds

    ./cached_time

    time per call: 0 nanoseconds

    (total) c2 = 999866408 (n = 500000000)

    `

    64 bit lohnt sich also.



  • Und hier nochmal auf meinem Desktop-System mit AMD-CPU (auch -m32):
    `./time

    time per call: 403 nanoseconds

    ./ftime

    time per call: 421 nanoseconds

    ./gettimeofday

    time per call: 403 nanoseconds

    ./clock_gettime

    time per call: 396 nanoseconds

    ./cached_time

    time per call: 0 nanoseconds

    (total) c2 = 1356654829 (n = 500000000) `

    Wäre ich nun B***-Redakteur, könnte ich das jetzt mit "Sensation: 64-bit Intel CPUs über 80x schneller als 32-bit AMD CPUs bei gleicher Taktrate!" betiteln.
    Mein nächster Rechner wird auf jeden Fall keine AMD-Hardware mehr haben 😞



  • asfas schrieb:

    Kann allerdings aus frühereren Tests deine Werte bestätigen (da hatte ich eher bis zu 2000-4000 CPU-Zyklen pro Call). Die niedrigen Werte irritieren mich gerade ein wenig - keine Ahnung, ob das in neueren Linux-Versionen effizienter geworden ist, oder ob es am 32->64 bit-Wechsel liegt, ob die Calls weniger kosten, wenn man sie oft hintereinander in einer Schleife aufruft (anzunehmen wäre das) oder ob ein anderer Grund vorliegt.

    DANKE für deine Tests!
    nur an was liegt es dann bei mir? an der Hardware?
    Hast du noch andere compile-options dazu gegeben?

    ich habe zwei gleiche Rechner-Hardware und die Performance ist gleich mies:

    ./time                       time per call: 298 nanoseconds
    ./ftime                      time per call: 450 nanoseconds
    ./gettimeofday               time per call: 403 nanoseconds
    ./clock_gettime_mono         time per call: 390 nanoseconds
    ./clock_gettime_mono_coarse  time per call: 344 nanoseconds
    ./clock_gettime_mono_raw     time per call: 389 nanoseconds
    ./clock_gettime_real         time per call: 385 nanoseconds
    ./clock_gettime_real_coarse  time per call: 337 nanoseconds
    
    [b]# ldd --version[/b]
    ldd (Ubuntu EGLIBC 2.15-0ubuntu10.5) 2.15
    
    [b]# gcc --version[/b]
    gcc (Ubuntu 4.8.1-2ubuntu1~12.04) 4.8.1
    
    [b]# cat /proc/cpuinfo[/b]
    model name      : Intel(R) Core(TM)2 CPU          6400  @ 2.13GHz
    model name      : Intel(R) Core(TM)2 CPU          6400  @ 2.13GHz
    
    [b]# uname -r[/b]
    3.2.0-38-generic
    
    [b]cat /proc/self/maps[/b]
    vdso wird angezeigt, wenn die test laufen
    
    [b]# cat /sys/devices/system/clocksource/clocksource0/available_clocksource[/b]
    tsc hpet acpi_pm
    
    [b]# cat /sys/devices/system/clocksource/clocksource0/current_clocksource[/b]
    tsc
    

    der zweite PC mit standard gcc vom ubuntu

    ./time                       time per call: 141 nanoseconds
    ./ftime                      time per call: 286 nanoseconds
    ./gettimeofday               time per call: 240 nanoseconds
    ./clock_gettime_mono         time per call: 389 nanoseconds
    ./clock_gettime_mono_coarse  time per call: 344 nanoseconds
    ./clock_gettime_mono_raw     time per call: 385 nanoseconds
    ./clock_gettime_real         time per call: 385 nanoseconds
    ./clock_gettime_real_coarse  time per call: 337 nanoseconds
    
    [b]# ldd --version[/b]
    ldd (Ubuntu EGLIBC 2.15-0ubuntu10.5) 2.15
    
    [b]# gcc --version[/b]
    gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
    
    [b]# cat /proc/cpuinfo[/b]
    model name      : Intel(R) Core(TM)2 CPU          6400  @ 2.13GHz
    model name      : Intel(R) Core(TM)2 CPU          6400  @ 2.13GHz
    
    [b]# uname -r[/b]
    3.2.0-30-generic-pae
    
    [b]# cat /sys/devices/system/clocksource/clocksource0/available_clocksource[/b]
    tsc hpet acpi_pm
    
    [b]# cat /sys/devices/system/clocksource/clocksource0/current_clocksource[/b]
    tsc
    

    Angeblich hängt viel von der glibc ab, aber da verwende ich auch fast die aktuelle Version
    TSC sollte auch die bessere/schnellere clock sein

    Liegt es rein am Intel Core2Duo?



  • Ich bleibe dabei: clock_gettime erzeugt keine wesentliche Last. Wenn ihr eine Dauer im Nanosekundenbereich als wesentlich anseht, dann stimmt mit dem Programm, welches es benutzt etwas nicht. Und ob ich nun 10ns oder 300ns benötige, um die Zeit zu ermitteln ist für mich kein Argument für oder gegen eine CPU.



  • Naja so würde ich das nicht sagen.
    Wie schon erwähnt habe ich habe eine Liste mit 10.000 Einträgen und die Abarbeitung der Liste wird gestoppt inkl. Zwischenzeiten.
    Es wird somit pro Eintrag die Zeit 6x abgefragt.
    Die Liste wird in einer Sekunde 15x abgearbeitet.
    Jedoch kann es auch sein, dass die Liste nur 1x in der Sekunde abgearbeitet wird oder sogar 5sec benötigt.

    Aber gehen wir mal davon aus, dass quasi alles glatt läuft

    Stoppuhr mit 300ns
    0,0000003 sec pro timeaufruf * 10000 Einträge * 6 Aufrufe * 15 Listenabarbeitungen = 0,27 sec.

    Stoppuhr mit 100ns
    0,0000001 sec pro timeaufruf * 10000 Einträge * 6 Aufrufe * 15 Listenabarbeitungen = 0,09 sec.

    Stoppuhr mit 10ns
    0,00000001 sec pro timeaufruf * 10000 Einträge * 6 Aufrufe * 15 Listenabarbeitungen = 0,009 sec.

    Ich finde schon, dass am Ende dies ein großer Unterschied ist.
    Ja klar schreibe ich jetzt div. Sachen um und spare mir sicher drei Abrufe pro Listenelement ein, aber trotzdem ist besser wenn man weniger Last hat.

    Mir stellt sich die Frage, ob es rein an der CPU liegt oder noch was anderes eine große Rolle spielt (irgendeine lib, eine Einstellung, Kernel, etc. was bei mir nicht passt)?

    @asfas
    Könntest du bitte den Test clock_gettime.c kopieren und die ganze Testreihe um ein normales CLOCK_MONOTONIC erweitern, damit man sehen kann wie sehr sich die CLOCK_MONOTONIC_COARSE Version von der anderen unterscheidet. Danke!



  • Das sind doch nur absolute Zeiten. 0,27 Sekunden sagen gar nichts aus, ob das lang ist oder nicht. Wenn die Gesamtlaufzeit 0,3 Sekunden ist, dann sind 0,27 Sekunden wesentlich. Läuft das Programm 30 Sekunden, dann sind 0,27 Sekunden vernachlässigbar.

    Ich nehme an, dass Du zwischen 2 Time-Aufrufen irgendetwas machst. Und in der Regel wird das etwas sein, was mindestens mal etliche Mikrosekunden braucht. Sagen wir mal 30, was extrem wenig wäre. Und wenn Du dann 300 ns für einen Time-Aufruf benötigst, dann sind das gerade mal 1%. Und Du optimierst an diesem 1% rum?

    Das meine ich mit wesentlich. Natürlich benötigt ein Time-Aufruf (welcher auch immer) eine Zeit. Aber ist diese wesentlich im Vergleich zu dem, was das Programm eigentlich macht?


Anmelden zum Antworten