C ++ obtenant du temps en millisecondes sous Linux - clock () ne semble pas fonctionner correctement


102

Sous Windows, clock()renvoie le temps en millisecondes, mais sur cette machine Linux sur laquelle je travaille, il l'arrondit au 1000 le plus proche, donc la précision est uniquement au niveau "deuxième" et non au niveau des millisecondes.

J'ai trouvé une solution avec Qt en utilisant la QTimeclasse, en instanciant un objet et en l'appelant start(), puis en appelant elapsed()pour obtenir le nombre de millisecondes écoulées.

J'ai eu de la chance parce que je travaille avec Qt pour commencer, mais j'aimerais une solution qui ne repose pas sur des bibliothèques tierces,

N'y a-t-il pas de moyen standard de le faire?

METTRE À JOUR

Veuillez ne pas recommander Boost.

Si Boost et Qt peuvent le faire, ce n'est sûrement pas magique, il doit y avoir quelque chose de standard qu'ils utilisent!


2
À propos de l'édition - mais le faire de manière portable est un peu pénible.
Anonyme le

Réponses:


37

Vous pouvez utiliser gettimeofday au début et à la fin de votre méthode, puis différencier les deux structures de retour. Vous obtiendrez une structure comme celle-ci:

struct timeval {
  time_t tv_sec;
  suseconds_t tv_usec;
}

EDIT: Comme le suggèrent les deux commentaires ci-dessous, clock_gettime (CLOCK_MONOTONIC) est un bien meilleur choix si vous l'avez disponible, ce qui devrait être presque partout ces jours-ci.

EDIT: Quelqu'un d'autre a commenté que vous pouvez également utiliser le C ++ moderne avec std :: chrono :: high_resolution_clock, mais cela n'est pas garanti pour être monotone. Utilisez plutôt regular_clock.


38
terrible pour un travail sérieux. De gros problèmes deux fois par an, quand quelqu'un fait des dates, et bien sûr la synchronisation NTP. Use clock_gettime (CLOCK_MONOTONIC,)
AndrewStone

9
@AndrewStone: l'heure UNIX ne change pas deux fois par an. Ou même une fois par an. Mais, oui, CLOCK_MONOTONICc'est idéal pour éviter les ajustements d'heure système localisés.
Courses de légèreté en orbite le

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
Pourquoi ajoutez-vous +0,5 à la différence?
Mahmoud Al-Qudsi

19
@Computer Guru, c'est une technique courante pour arrondir les valeurs positives. Lorsque la valeur est tronquée à une valeur entière, tout ce qui est compris entre 0,0 et 0,4999 ... avant que l'addition ne soit tronquée à 0, et entre 0,5 et 0,9999 ... est tronquée à 1.
Mark Ransom

8
tv_usec n'est pas des millisecondes, c'est des microsecondes.
NebulaFox

13
terrible pour un travail sérieux. De gros problèmes deux fois par an, quand quelqu'un fait des rendez-vous, et bien sûr la synchronisation NTP
AndrewStone

14
@AndrewStone a raison, utilisez clock_gettime (2) avec CLOCK_REALTIME pour comparer les heures sur le même ordinateur. À partir de la page de manuel gettimeofday (2): POSIX.1-2008 marks gettimeofday() as obsolete, recommending the use of clock_gettime(2) instead. @CTT, pourriez-vous mettre à jour l'exemple en changeant le struct timevalen struct timespec, et gettimeofday(&start, NULL)en clock_gettime(CLOCK_MONOTONIC, &start)pour que les gens n'aient pas de problèmes?
Bobby Powers le

58

Veuillez noter que clockne mesure pas l' heure de l'horloge murale. Cela signifie que si votre programme prend 5 secondes, clockne mesurera pas nécessairement 5 secondes, mais pourrait plus (votre programme pourrait exécuter plusieurs threads et pourrait donc consommer plus de CPU que le temps réel) ou moins. Il mesure une approximation du temps CPU utilisé. Pour voir la différence, considérez ce 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;
}

Il sort sur mon système

$ difference: 0

Parce que tout ce que nous avons fait était de dormir et de ne pas utiliser de temps CPU! Cependant, en utilisant gettimeofdaynous obtenons ce que nous voulons (?)

#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;
}

Sorties sur mon système

$ difference: 5

Si vous avez besoin de plus de précision mais que vous souhaitez obtenir du temps CPU , vous pouvez envisager d'utiliser la getrusagefonction.


⁺¹ à propos de la mention a sleep()- Je pense déjà poser une question (pourquoi cela fonctionne-t-il bien pour tout le monde sauf moi?!) , Lorsque vous avez trouvé votre réponse.
Hi-Angel

18

Je recommande également les outils proposés par Boost. Soit le Boost Timer mentionné, soit pirater quelque chose de Boost.DateTime ou il y a une nouvelle bibliothèque proposée dans le bac à sable - Boost.Chrono : Ce dernier remplacera le Timer et comprendra:

  • Les utilitaires de temps de la bibliothèque standard C ++ 0x, notamment:
    • Modèle de classe duration
    • Modèle de classe time_point
    • Horloges:
      • system_clock
      • monotonic_clock
      • high_resolution_clock
  • timerModèle de classe , avec typedefs:
    • system_timer
    • monotonic_timer
    • high_resolution_timer
  • Horloges et minuteries de processus:
    • process_clock, capturant les temps réels, CPU utilisateur et CPU système.
    • process_timer, capturant les temps réels écoulés entre l'UC utilisateur et l'UC système.
    • run_timer, rapport pratique de | process_timer | résultats.
  • L'arithmétique rationnelle à la compilation de la bibliothèque standard C ++ 0x.

Voici la source de la liste des fonctionnalités


Pour l'instant, vous pouvez utiliser le Boost Timer, puis migrer gracieusement vers Chrono lorsqu'il est examiné / accepté.
Anonyme le

13

J'ai écrit un Timercours basé sur la réponse de CTT . Il peut être utilisé de la manière suivante:

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

Voici sa mise en œuvre:

#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
C'est cool mais le "nsecondes" est trompeur car timeval ne tient pas les nanosecondes, il tient les microsecondes, donc je suggérerais que les gens appellent cela "useconds".
pho0

Merci. Correction faite.
Chris Redford

9

Si vous n'avez pas besoin que le code soit portable sur les anciens unices, vous pouvez utiliser clock_gettime (), qui vous donnera l'heure en nanosecondes (si votre processeur prend en charge cette résolution). C'est POSIX, mais depuis 2001.


4

clock () a une résolution souvent assez médiocre. Si vous souhaitez mesurer le temps au niveau de la milliseconde, une alternative consiste à utiliser clock_gettime (), comme expliqué dans cette question.

(N'oubliez pas que vous devez créer un lien avec -lrt sous Linux).


4

Avec C ++ 11 et std::chrono::high_resolution_clockvous pouvez le faire:

#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;
}

Production:

Delta t2-t1: 3 milliseconds

Lien vers la démo: http://cpp.sh/2zdtu


2

clock () ne renvoie pas les millisecondes ou les secondes sous Linux. Habituellement, clock () renvoie des microsecondes sur un système Linux. La bonne façon d'interpréter la valeur renvoyée par clock () est de la diviser par CLOCKS_PER_SEC pour savoir combien de temps s'est écoulé.


pas dans la boîte sur laquelle je travaille! De plus, je suis en divisant par CLOCKS_PER_SEC, mais il est inutile parce que la résolution est seulement à la seconde
Hasen

Eh bien pour être honnête, les unités sont en microsecondes (CLOCKS_PER_SEC vaut 1000000 sur tous les systèmes POSIX). Juste il a une résolution de secondes. :-P.
Evan Teran

1

Cela devrait fonctionner ... testé sur un mac ...

#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);
}

Ouais ... lancez-le deux fois et soustrayez ...


1

Dans la norme POSIX, clocksa valeur de retour est définie en termes du symbole CLOCKS_PER_SEC et une implémentation est libre de la définir de n'importe quelle manière appropriée. Sous Linux, j'ai eu de la chance avec la times()fonction.


1

gettimeofday - le problème est qu'il peut avoir des valeurs inférieures si vous changez votre horloge matérielle (avec NTP par exemple) Boost - non disponible pour ce projet clock () - renvoie généralement un entier de 4 octets, ce qui signifie que sa capacité est faible, et après un certain temps, il renvoie des nombres négatifs.

Je préfère créer ma propre classe et la mettre à jour toutes les 10 millisecondes, donc cette façon est plus flexible, et je peux même l'améliorer pour avoir des abonnés.

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;

pour le rafraîchir, j'utilise 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); 
.....

Regardez setitimer et les ITIMER_VIRTUAL et ITIMER_REAL.

N'utilisez pas les fonctions d'alarme ou d'ualarm, vous aurez une faible précision lorsque votre processus sera dur.



0

En tant que mise à jour, apparaît que sur windows clock () mesure l'heure de l'horloge murale (avec la précision CLOCKS_PER_SEC)

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

tandis que sous Linux, il mesure le temps CPU à travers les cœurs utilisés par le processus actuel

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

et (il semble, et comme indiqué par l'affiche originale) en fait avec moins de précision que CLOCKS_PER_SEC, bien que cela dépende peut-être de la version spécifique de Linux.


0

J'aime la méthode Hola Soy de ne pas utiliser gettimeofday (). Cela m'est arrivé sur un serveur en cours d'exécution, l'administrateur a changé le fuseau horaire. L'horloge a été mise à jour pour afficher la même valeur locale (correcte). Cela a provoqué un décalage de 2 heures de la fonction time () et gettimeofday () et tous les horodatages de certains services sont restés bloqués.


0

J'ai écrit une C++classe en utilisant timeb.

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

Fonctions des membres:

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);
}

Exemple d'utilisation:

#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;
}

La sortie sur mon ordinateur est «19». La précision de la msTimerclasse est de l'ordre de la milliseconde. Dans l'exemple d'utilisation ci-dessus, le temps total d'exécution occupé par la forboucle -loop est suivi. Cette fois, le système d'exploitation entre et sort du contexte d'exécution en main()raison du multitâche.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.