web-dev-qa-db-fra.com

Temps d'exécution du programme C

J'ai un programme C qui vise à être exécuté en parallèle sur plusieurs processeurs. Je dois pouvoir enregistrer le temps d'exécution (qui peut aller de 1 seconde à plusieurs minutes). J'ai cherché des réponses, mais elles semblent toutes suggérer d'utiliser la fonction clock(), qui consiste ensuite à calculer le nombre d'horloges prises par le programme divisé par la valeur Clocks_per_second.

Je ne suis pas sûr de savoir comment la valeur de Clocks_per_second est calculée?

En Java, je prends simplement l'heure actuelle en millisecondes avant et après l'exécution.

Y a-t-il une chose semblable dans C J'ai jeté un coup d'œil, mais je n'arrive pas à trouver le moyen d'obtenir quelque chose de mieux qu'une seconde résolution.

Je suis également conscient qu'un profileur serait une option, mais je cherche à implémenter moi-même une minuterie.

Merci

190
Roger

CLOCKS_PER_SEC est une constante qui est déclarée dans <time.h>. Pour obtenir le temps CPU utilisé par une tâche dans une application C, utilisez:

clock_t begin = clock();

/* here, do your time-consuming job */

clock_t end = clock();
double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;

Notez que cela retourne l'heure en tant que type à virgule flottante. Cela peut être plus précis qu'une seconde (par exemple, vous mesurez 4,52 secondes). La précision dépend de l'architecture. sur les systèmes modernes, vous obtenez facilement 10 ms ou moins, mais sur les anciennes machines Windows (de l’ère Win98), il était plus proche de 60 ms.

clock() est le standard C; ça marche "partout". Il existe des fonctions spécifiques au système, telles que getrusage() sur des systèmes de type Unix.

La System.currentTimeMillis() de Java ne mesure pas la même chose. C'est une "horloge murale": elle peut vous aider à mesurer le temps d'exécution du programme, mais elle ne vous indique pas combien de temps CPU a été utilisé. Sur un système multitâche (c’est-à-dire tous), ceux-ci peuvent être très différents.

309
Thomas Pornin

Si vous utilisez le shell Unix pour l'exécution, vous pouvez utiliser la commande time.

faire

$ time ./a.out

en supposant a.out que l'exécutable vous donnera le temps nécessaire pour l'exécuter

107
S..K

Vous voulez fonctionnellement ceci:

#include <sys/time.h>

struct timeval  tv1, tv2;
gettimeofday(&tv1, NULL);
/* stuff to do! */
gettimeofday(&tv2, NULL);

printf ("Total time = %f seconds\n",
         (double) (tv2.tv_usec - tv1.tv_usec) / 1000000 +
         (double) (tv2.tv_sec - tv1.tv_sec));

Notez que cela se mesure en microsecondes, pas seulement en secondes.

58
Wes Hardaker

En plain vanille C:

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

int main()
{
    clock_t tic = clock();

    my_expensive_function_which_can_spawn_threads();

    clock_t toc = clock();

    printf("Elapsed: %f seconds\n", (double)(toc - tic) / CLOCKS_PER_SEC);

    return 0;
}
54
Alexandre C.

La plupart des programmes simples ont un temps de calcul en millisecondes. Donc, je suppose que vous trouverez cela utile.

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

int main(){
    clock_t start = clock();
    // Execuatable code
    clock_t stop = clock();
    double elapsed = (double)(stop - start) * 1000.0 / CLOCKS_PER_SEC;
    printf("Time elapsed in ms: %f", elapsed);
}

Si vous voulez calculer le runtime du programme entier et que vous êtes sur un système Unix, exécutez votre programme en utilisant la commande time comme ceci time ./a.out

12
adimoh

La réponse de Thomas Pornin en macros:

#define TICK(X) clock_t X = clock()
#define TOCK(X) printf("time %s: %g sec.\n", (#X), (double)(clock() - (X)) / CLOCKS_PER_SEC)

Utilisez-le comme ceci:

TICK(TIME_A);
functionA();
TOCK(TIME_A);

TICK(TIME_B);
functionB();
TOCK(TIME_B);

Sortie:

time TIME_A: 0.001652 sec.
time TIME_B: 0.004028 sec.
8
hklel

Beaucoup de réponses suggèrent clock() puis CLOCKS_PER_SEC à partir de time.h. C'est probablement une mauvaise idée, car c'est ce que dit mon fichier /bits/time.h:

/* ISO/IEC 9899:1990 7.12.1: <time.h>
The macro `CLOCKS_PER_SEC' is the number per second of the value
returned by the `clock' function. */
/* CAE XSH, Issue 4, Version 2: <time.h>
The value of CLOCKS_PER_SEC is required to be 1 million on all
XSI-conformant systems. */
#  define CLOCKS_PER_SEC  1000000l

#  if !defined __STRICT_ANSI__ && !defined __USE_XOPEN2K
/* Even though CLOCKS_PER_SEC has such a strange value CLK_TCK
presents the real value for clock ticks per second for the system.  */
#   include <bits/types.h>
extern long int __sysconf (int);
#   define CLK_TCK ((__clock_t) __sysconf (2))  /* 2 is _SC_CLK_TCK */
#  endif

Donc, CLOCKS_PER_SEC peut être défini comme 1000000, selon les options que vous utilisez pour la compilation, ce qui ne semble donc pas être une bonne solution.

8
Stephen

Vous devez prendre en compte que mesurer le time qui a nécessité l'exécution d'un programme dépend beaucoup de la charge de la machine à ce moment précis.

Sachant que l’obtention de l’heure actuelle en C peut être obtenue de différentes manières, la plus simple est:

#include <time.h>

#define CPU_TIME (getrusage(RUSAGE_SELF,&ruse), ruse.ru_utime.tv_sec + \
  ruse.ru_stime.tv_sec + 1e-6 * \
  (ruse.ru_utime.tv_usec + ruse.ru_stime.tv_usec))

int main(void) {
    time_t start, end;
    double first, second;

    // Save user and CPU start time
    time(&start);
    first = CPU_TIME;

    // Perform operations
    ...

    // Save end time
    time(&end);
    second = CPU_TIME;

    printf("cpu  : %.2f secs\n", second - first); 
    printf("user : %d secs\n", (int)(end - start));
}

J'espère que ça aide.

Cordialement!

4
redent84

(Toutes les réponses ici manquent, si votre administrateur système change l'heure du système ou si votre fuseau horaire a des heures d'hiver et d'été différentes. Par conséquent ...)

Sous Linux: clock_gettime(CLOCK_MONOTONIC_RAW, &time_variable); Il n'est pas affecté si l'administrateur système change l'heure ou si vous résidez dans un pays où l'heure d'hiver est différente de l'heure d'été, etc.

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

#include <unistd.h> /* for sleep() */

int main() {
    struct timespec begin, end;
    clock_gettime(CLOCK_MONOTONIC_RAW, &begin);

    sleep(1);      // waste some time

    clock_gettime(CLOCK_MONOTONIC_RAW, &end);

    printf ("Total time = %f seconds\n",
            (end.tv_nsec - begin.tv_nsec) / 1000000000.0 +
            (end.tv_sec  - begin.tv_sec));

}

man clock_gettime déclare:

CLOCK_MONOTONIC
              Clock  that  cannot  be set and represents monotonic time since some unspecified starting point.  This clock is not affected by discontinuous jumps in the system time
              (e.g., if the system administrator manually changes the clock), but is affected by the incremental adjustments performed by adjtime(3) and NTP.
3
JohnSll

ANSI C spécifie uniquement les fonctions temporelles de seconde précision. Cependant, si vous travaillez dans un environnement POSIX, vous pouvez utiliser la fonction gettimeofday () qui fournit une résolution en microsecondes du temps écoulé depuis l’époque UNIX.

En remarque, je ne recommanderais pas d’utiliser clock (), car il est mal implémenté sur de nombreux systèmes (sinon tous?) Et manque de précision, outre le fait qu’il se réfère uniquement au temps que votre programme a passé sur le processeur et pas la durée de vie totale du programme, ce qui, selon votre question, est ce que je suppose que vous souhaitez mesurer.

3
Shinnok

Toutes les solutions ne fonctionnent pas dans mon système.

Je peux utiliser

#include <time.h>

double difftime(time_t time1, time_t time0);
2
Ankit Chilamatur
    #include<time.h>
    #include<stdio.h>
    int main(){
clock_t begin=clock();

    int i;
for(i=0;i<100000;i++){
printf("%d",i);

}
clock_t end=clock();
printf("Time taken:%lf",(double)(end-begin)/CLOCKS_PER_SEC);
}

Ce programme fonctionnera comme un charme.

2
Ravi Kumar Yadav

J'ai trouvé que l'horloge habituelle (), recommande tout le monde ici, pour une raison quelconque, varie énormément d'une exécution à l'autre, même pour du code statique sans effets secondaires, comme dessiner à l'écran ou lire des fichiers. Cela peut être dû au fait que le processeur change de mode de consommation d'énergie, que le système d'exploitation donne des priorités différentes, etc.

Ainsi, le seul moyen d'obtenir de manière fiable le même résultat à chaque fois avec clock () est d'exécuter le code mesuré dans une boucle plusieurs fois (pendant plusieurs minutes), en prenant des précautions pour empêcher le compilateur de l'optimiser: les compilateurs modernes peuvent précalculer le code sans effets secondaires s'exécutant dans une boucle et déplacez-le hors de la boucle, comme si vous utilisiez une entrée aléatoire pour chaque itération.

Lorsque suffisamment d'échantillons sont collectés dans un tableau, on trie ce tableau et prend l'élément médian, appelé médiane. La médiane est meilleure que la moyenne, car elle supprime les écarts extrêmes, comme par exemple un antivirus prenant tout le processeur ou un système d'exploitation faisant des mises à jour.

Voici un utilitaire simple permettant de mesurer les performances d’exécution du code C/C++, en faisant la moyenne des valeurs proches de la médiane: https://github.com/saniv/gauge

Je suis moi-même toujours à la recherche d'un moyen plus robuste et plus rapide de mesurer le code. On pourrait probablement essayer d’exécuter le code dans des conditions contrôlées sur du "bare metal" sans aucun système d’exploitation, mais cela donnera un résultat irréaliste car, en réalité, le système d’exploitation est impliqué.

x86 possède ces compteurs de performances matérielles, qui incluent le nombre réel d’instructions exécutées, mais ils sont difficiles à accéder sans aide du système d’exploitation, difficiles à interpréter et ont leurs propres problèmes ( http://archive.gamedev.net/archive /reference/articles/article213.html ). Néanmoins, ils pourraient être utiles pour étudier la nature du goulot d'étranglement (accès aux données ou calculs réels sur ces données).

1
SmugLispWeenie

Certains trouveront peut-être un autre type de contribution utile: cette méthode de mesure du temps m'a été proposée dans le cadre d'un cours universitaire sur la programmation GPGPU avec NVidia CUDA ( description du cours ). Il combine des méthodes vues dans des publications précédentes, et je le poste simplement parce que les exigences lui donnent de la crédibilité:

unsigned long int elapsed;
struct timeval t_start, t_end, t_diff;
gettimeofday(&t_start, NULL);

// perform computations ...

gettimeofday(&t_end, NULL);
timeval_subtract(&t_diff, &t_end, &t_start);
elapsed = (t_diff.tv_sec*1e6 + t_diff.tv_usec);
printf("GPU version runs in: %lu microsecs\n", elapsed);

Je suppose que vous pourriez multiplier avec par exemple 1.0 / 1000.0 pour obtenir l'unité de mesure qui vous convient.

0
Alexander