C ++, das unter Linux Millisekunden Zeit erhält - clock () scheint nicht richtig zu funktionieren


102

Gibt unter Windows clock()die Zeit in Millisekunden zurück, aber auf dieser Linux-Box, an der ich arbeite, wird sie auf die nächste 1000 gerundet, sodass die Genauigkeit nur auf der "zweiten" Ebene und nicht auf der Millisekunden-Ebene liegt.

Ich habe mit Qt eine Lösung gefunden, bei der die QTimeKlasse verwendet, ein Objekt instanziiert und aufgerufen start()und dann aufgerufen wurde elapsed(), um die Anzahl der verstrichenen Millisekunden abzurufen.

Ich hatte ein bisschen Glück, weil ich zunächst mit Qt zusammenarbeite, aber ich hätte gerne eine Lösung, die nicht auf Bibliotheken von Drittanbietern basiert.

Gibt es keinen Standardweg, um dies zu tun?

AKTUALISIEREN

Bitte empfehlen Sie Boost nicht ..

Wenn Boost und Qt das können, ist es sicherlich keine Magie, es muss einen Standard geben, den sie verwenden!


2
Über das Bearbeiten - aber es auf tragbare Weise zu tun, ist ein Schmerz.
Anonym

Antworten:


37

Sie können gettimeofday zu Beginn und am Ende Ihrer Methode verwenden und dann die beiden Rückgabestrukturen unterscheiden. Sie erhalten eine Struktur wie die folgende:

struct timeval {
  time_t tv_sec;
  suseconds_t tv_usec;
}

BEARBEITEN: Wie aus den beiden folgenden Kommentaren hervorgeht, ist clock_gettime (CLOCK_MONOTONIC) eine viel bessere Wahl, wenn Sie es zur Verfügung haben, was heutzutage fast überall sein sollte.

EDIT: Jemand anderes hat kommentiert, dass Sie auch modernes C ++ mit std :: chrono :: high_resolution_clock verwenden können, aber das ist nicht garantiert monoton. Verwenden Sie stattdessen stetige Uhr.


38
schrecklich für ernsthafte Arbeit. Große Probleme zweimal im Jahr, wenn jemand Datumsangaben macht, und natürlich NTP-Synchronisierung. Verwenden Sie clock_gettime (CLOCK_MONOTONIC,)
AndrewStone

9
@ AndrewStone: Die UNIX-Zeit ändert sich nicht zweimal pro Jahr. Oder sogar einmal im Jahr. Aber ja, CLOCK_MONOTONICist großartig, um lokalisierte Systemzeitanpassungen zu vermeiden.
Leichtigkeitsrennen im Orbit

138
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
    struct timeval start, end;

    long mtime, seconds, useconds;    

    gettimeofday(&start, NULL);
    usleep(2000);
    gettimeofday(&end, NULL);

    seconds  = end.tv_sec  - start.tv_sec;
    useconds = end.tv_usec - start.tv_usec;

    mtime = ((seconds) * 1000 + useconds/1000.0) + 0.5;

    printf("Elapsed time: %ld milliseconds\n", mtime);

    return 0;
}

4
Warum addieren Sie +0,5 zur Differenz?
Mahmoud Al-Qudsi

19
@ Computer Guru, es ist eine übliche Technik zum Runden positiver Werte. Wenn der Wert auf einen ganzzahligen Wert gekürzt wird, wird alles zwischen 0,0 und 0,4999 ... bevor die Addition auf 0 und zwischen 0,5 und 0,9999 ... auf 1 gekürzt wird.
Mark Ransom

8
tv_usec ist keine Millisekunde, sondern Mikrosekunden.
NebulaFox

13
schrecklich für ernsthafte Arbeit. Große Probleme zweimal im Jahr, wenn jemand Datumsangaben macht, und natürlich NTP-Synchronisierung
AndrewStone

14
@AndrewStone ist richtig. Verwenden Sie clock_gettime (2) mit CLOCK_REALTIME, um die Zeiten auf demselben Computer zu vergleichen. Vom gettimeofday (2) manpage: POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead. @CTT, Sie das Beispiel , indem die Aktualisierung konnte struct timevalzu struct timespec, und gettimeofday(&start, NULL)zu clock_gettime(CLOCK_MONOTONIC, &start)so , dass die Menschen in Schwierigkeiten nicht laufen können?
Bobby Powers

58

Bitte beachten Sie, dass die clockWanduhrzeit nicht gemessen wird. Das heißt, wenn Ihr Programm 5 Sekunden dauert, clockmisst es nicht unbedingt 5 Sekunden, sondern könnte mehr (Ihr Programm könnte mehrere Threads ausführen und somit mehr CPU als Echtzeit verbrauchen) oder weniger. Es misst eine Annäherung an die verwendete CPU-Zeit . Um den Unterschied zu sehen, betrachten Sie diesen Code

#include <iostream>
#include <ctime>
#include <unistd.h>

int main() {
    std::clock_t a = std::clock();
    sleep(5); // sleep 5s
    std::clock_t b = std::clock();

    std::cout << "difference: " << (b - a) << std::endl;
    return 0;
}

Es wird auf meinem System ausgegeben

$ difference: 0

Weil wir nur geschlafen haben und keine CPU-Zeit verbraucht haben! Mit gettimeofdaybekommen wir jedoch, was wir wollen (?)

#include <iostream>
#include <ctime>
#include <unistd.h>
#include <sys/time.h>

int main() {
    timeval a;
    timeval b;

    gettimeofday(&a, 0);
    sleep(5); // sleep 5s
    gettimeofday(&b, 0);

    std::cout << "difference: " << (b.tv_sec - a.tv_sec) << std::endl;
    return 0;
}

Ausgänge auf meinem System

$ difference: 5

Wenn Sie mehr Präzision benötigen, aber CPU-Zeit erhalten möchten, können Sie die getrusageFunktion verwenden.


⁺¹ über Erwähnung a sleep()- Es wird bereits angenommen, dass ich eine Frage stelle (warum funktioniert es für alle außer mir?!) , Wenn Ihre Antwort gefunden wurde.
Hi-Angel

18

Ich empfehle auch die von Boost angebotenen Tools. Entweder der erwähnte Boost-Timer oder etwas aus Boost.DateTime hacken oder es gibt eine neue vorgeschlagene Bibliothek in der Sandbox - Boost.Chrono : Dieser letzte wird ein Ersatz für den Timer sein und Folgendes bieten :

  • Die Zeitdienstprogramme der C ++ 0x Standard Library, einschließlich:
    • Klassenvorlage duration
    • Klassenvorlage time_point
    • Uhren:
      • system_clock
      • monotonic_clock
      • high_resolution_clock
  • Klassenvorlage timermit typedefs:
    • system_timer
    • monotonic_timer
    • high_resolution_timer
  • Prozessuhren und Timer:
    • process_clockErfassen von Real-, Benutzer-CPU- und System-CPU-Zeiten.
    • process_timerErfassen der verstrichenen Real-, Benutzer-CPU- und System-CPU-Zeiten.
    • run_timer, bequeme Berichterstattung über | process_timer | Ergebnisse.
  • Die rationale Arithmetik zur Kompilierungszeit der C ++ 0x-Standardbibliothek.

Hier ist die Quelle der Funktionsliste


Im Moment können Sie den Boost-Timer verwenden und dann ordnungsgemäß zu Chrono migrieren, wenn er überprüft / akzeptiert wird.
Anonym

13

Ich habe eine TimerKlasse geschrieben, die auf der Antwort von CTT basiert . Es kann folgendermaßen verwendet werden:

Timer timer = Timer();
timer.start();
/* perform task */
double duration = timer.stop();
timer.printTime(duration);

Hier ist seine Implementierung:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
using namespace std;

class Timer {
private:

    timeval startTime;

public:

    void start(){
        gettimeofday(&startTime, NULL);
    }

    double stop(){
        timeval endTime;
        long seconds, useconds;
        double duration;

        gettimeofday(&endTime, NULL);

        seconds  = endTime.tv_sec  - startTime.tv_sec;
        useconds = endTime.tv_usec - startTime.tv_usec;

        duration = seconds + useconds/1000000.0;

        return duration;
    }

    static void printTime(double duration){
        printf("%5.6f seconds\n", duration);
    }
};

2
Das ist cool, aber die "nseconds" sind irreführend, weil timeval keine Nanosekunden, sondern Mikrosekunden enthält. Ich würde daher vorschlagen, dass die Leute dies "useconds" nennen.
Pho0

Vielen Dank. Korrektur vorgenommen.
Chris Redford

9

Wenn Sie nicht möchten, dass der Code auf alte Unices portierbar ist, können Sie clock_gettime () verwenden, mit dem Sie die Zeit in Nanosekunden angeben können (wenn Ihr Prozessor diese Auflösung unterstützt). Es ist POSIX, aber ab 2001.


4

clock () hat oft eine ziemlich miese Auflösung. Wenn Sie die Zeit im Millisekundenbereich messen möchten, können Sie alternativ clock_gettime () verwenden, wie in dieser Frage erläutert.

(Denken Sie daran, dass Sie unter Linux eine Verknüpfung mit -lrt herstellen müssen.)


4

Mit C ++ 11 std::chrono::high_resolution_clockkönnen Sie dies tun:

#include <iostream>
#include <chrono>
#include <thread>
typedef std::chrono::high_resolution_clock Clock;

int main()
{
    std::chrono::milliseconds three_milliseconds{3};

    auto t1 = Clock::now();
    std::this_thread::sleep_for(three_milliseconds);
    auto t2 = Clock::now();

    std::cout << "Delta t2-t1: " 
              << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count()
              << " milliseconds" << std::endl;
}

Ausgabe:

Delta t2-t1: 3 milliseconds

Link zur Demo: http://cpp.sh/2zdtu


2

clock () gibt unter Linux keine Millisekunden oder Sekunden zurück. Normalerweise gibt clock () auf einem Linux-System Mikrosekunden zurück. Die richtige Methode zur Interpretation des von clock () zurückgegebenen Werts besteht darin, ihn durch CLOCKS_PER_SEC zu teilen, um herauszufinden, wie viel Zeit vergangen ist.


nicht in der Box, an der ich arbeite! plus, ich bin Dividieren durch CLOCKS_PER_SEC, aber es ist sinnlos , weil die Auflösung nur bis zum zweiten ist
hase

Um fair zu sein, die Einheiten sind Mikrosekunden (CLOCKS_PER_SEC ist 1000000 auf allen POSIX-Systemen). Nur hat es Sekunden Auflösung. :-P.
Evan Teran

1

Dies sollte funktionieren ... auf einem Mac getestet ...

#include <stdio.h>
#include <sys/time.h>

int main() {
        struct timeval tv;
        struct timezone tz;
        struct tm *tm;
        gettimeofday(&tv,&tz);
        tm=localtime(&tv.tv_sec);
        printf("StartTime: %d:%02d:%02d %d \n", tm->tm_hour, tm->tm_min, tm->tm_sec, tv.tv_usec);
}

Ja ... zweimal ausführen und subtrahieren ...


1

Im POSIX-Standard clockist der Rückgabewert anhand des Symbols CLOCKS_PER_SEC definiert, und eine Implementierung kann diesen auf jede bequeme Weise definieren. Unter Linux hatte ich viel Glück mit der times()Funktion.


1

gettimeofday - das Problem ist, dass es niedrigere Werte geben kann, wenn Sie die Hardware-Uhr ändern (z. B. mit NTP). Boost - für diese Projektuhr nicht verfügbar () - gibt normalerweise eine 4-Byte-Ganzzahl zurück, was bedeutet, dass die Kapazität niedrig ist, und Nach einiger Zeit werden negative Zahlen zurückgegeben.

Ich ziehe es vor, meine eigene Klasse zu erstellen und alle 10 Millisekunden zu aktualisieren, damit dieser Weg flexibler ist und ich ihn sogar verbessern kann, um Abonnenten zu haben.

class MyAlarm {
static int64_t tiempo;
static bool running;
public:
static int64_t getTime() {return tiempo;};
static void callback( int sig){
    if(running){
        tiempo+=10L;
    }
}
static void run(){ running = true;}
};

int64_t MyAlarm::tiempo = 0L;
bool MyAlarm::running = false;

Um es zu aktualisieren, benutze ich Setitimer:

int main(){
struct sigaction sa; 
struct itimerval timer; 

MyAlarm::run();
memset (&sa, 0, sizeof (sa)); 
sa.sa_handler = &MyAlarm::callback; 

sigaction (SIGALRM, &sa, NULL); 


timer.it_value.tv_sec = 0; 
timer.it_value.tv_usec = 10000; 



timer.it_interval.tv_sec = 0; 
timer.it_interval.tv_usec = 10000; 


setitimer (ITIMER_REAL, &timer, NULL); 
.....

Schauen Sie sich Setitimer und ITIMER_VIRTUAL und ITIMER_REAL an.

Verwenden Sie nicht die Alarm- oder ualarm-Funktionen, da Sie eine geringe Präzision haben, wenn Ihr Prozess eine harte Arbeit erhält.



0

Als Update erscheint, dass unter Windows clock () die Wanduhrzeit misst (mit CLOCKS_PER_SEC-Genauigkeit)

 http://msdn.microsoft.com/en-us/library/4e2ess30(VS.71).aspx

Unter Linux wird die CPU-Zeit über die Kerne hinweg gemessen, die vom aktuellen Prozess verwendet werden

http://www.manpagez.com/man/3/clock

und (wie es scheint und wie auf dem Originalplakat vermerkt) tatsächlich mit geringerer Genauigkeit als CLOCKS_PER_SEC, obwohl dies möglicherweise von der spezifischen Linux-Version abhängt.


0

Ich mag die Hola Soy-Methode, gettimeofday () nicht zu verwenden. Es ist mir auf einem laufenden Server passiert, dass der Administrator die Zeitzone geändert hat. Die Uhr wurde aktualisiert, um denselben (korrekten) lokalen Wert anzuzeigen. Dies führte dazu, dass die Funktionszeit () und gettimeofday () um 2 Stunden verschoben wurden und alle Zeitstempel in einigen Diensten stecken blieben.


0

Ich habe eine C++Klasse mit geschrieben timeb.

#include <sys/timeb.h>
class msTimer 
{
public:
    msTimer();
    void restart();
    float elapsedMs();
private:
    timeb t_start;
};

Mitgliedsfunktionen:

msTimer::msTimer() 
{ 
    restart(); 
}

void msTimer::restart() 
{ 
    ftime(&t_start); 
}

float msTimer::elapsedMs() 
{
    timeb t_now;
    ftime(&t_now);
    return (float)(t_now.time - t_start.time) * 1000.0f +
           (float)(t_now.millitm - t_start.millitm);
}

Anwendungsbeispiel:

#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char** argv) 
{
    msTimer t;
    for (int i = 0; i < 5000000; i++)
        ;
    std::cout << t.elapsedMs() << endl;
    return 0;
}

Die Ausgabe auf meinem Computer ist '19'. Die Genauigkeit der msTimerKlasse liegt in der Größenordnung von Millisekunden. Im obigen Verwendungsbeispiel wird die Gesamtzeit der Ausführung, die von der forSchleife benötigt wird, verfolgt. Diese Zeit beinhaltete das Ein- und Ausschalten des Betriebssystems in den Ausführungskontext main()aufgrund von Multitasking.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.