3
votes

Pourquoi le temps d'exécution du même code sur le même ordinateur pourrait-il être différent?

Je suis nouveau dans la programmation C, j'ai écrit du code et je veux obtenir son exécution. Voici ce que j'ai fait. Chaque fois que j'exécute mon code, j'obtiens une valeur d'exécution différente. Est ce bien? ou y a-t-il un problème avec mon code?

int main(int argc, char *argv[])
{
    time_t start,end;
    start=clock();
    // this part is some operation

    end=clock();
    int running_time=end-start;
    printf("Time taken: %d",running_time);
    return 0;
}

c

5 commentaires

Non, il n'y a rien de "mal" avec votre code (sauf qu'il est incomplet: vous avez laissé un fw lignes, donc il ne se compilera pas comme indiqué). C'est simplement que le "temps de démarrage" d'une application est "indéterminé". Tout comme la latence pour afficher les E / S de texte tamponné "printf ()" sur votre écran. À eux seuls, ces facteurs pourraient expliquer tout écart que vous constatez.


Il n'y a rien de fondamentalement faux avec le code d'instrumentation que vous avez montré tant que vous êtes intéressé à montrer seulement "une approximation du temps processeur utilisé par" le code que vous n'avez pas montré. Je vous recommande de profiler tout votre code.


SUGGESTION: Lisez ce Optimisation de la programmation, Paul Hsieh . Il vous donnera quelques bonnes idées sur les «performances» et des suggestions sur la façon d'écrire des «benchmarks» plus utiles et réalistes.


Les systèmes d'exploitation Windows et Linux sont tels qu'ils ne donnent aucune garantie sur le timing. De plus, toute fonction qui vous donne le temps a une résolution, donc clock () renvoie la même valeur pour un segment de temps, une autre valeur (supérieure à +1) pour le segment de temps suivant, et ainsi de suite.


Notez que la fonction clock () renvoie des valeurs clock_t et non des valeurs time_t . La valeur mesurée par clock () est signalée avec CLOCKS_PER_SEC compté pour chaque seconde écoulée. Il mesure également la durée du processeur utilisée, qui n'est pas la même que le temps écoulé (horloge murale). Soyez juste prudent dans votre interprétation des résultats. (Néanmoins, ce que vous faites est une façon de mesurer le temps, et le temps nécessaire peut varier, en fonction d'une grande variété de facteurs principalement liés à ce qui fonctionne sur le système en même temps.)


3 Réponses :


1
votes

Il est très normal que la durée d'exécution varie, car votre ordinateur exécute probablement beaucoup de choses (y compris votre système d'exploitation), pas seulement ce morceau de code, et cela affectera la vitesse d'horloge.

Sur un ordinateur où la consommation de traitement est très stable, le temps d'exécution devrait rester similaire cependant.

Il n'y a rien de mal avec votre code.


0 commentaires

4
votes

Rien de mal avec le code. Sa juste compréhension du planificateur du système d'exploitation pour l'exécution de votre programme, cela varie à tout moment.


0 commentaires

2
votes

Cela dépend des variations que vous observez. Dans les ordinateurs modernes, tout est conçu pour optimiser statistiquement le temps d'exécution moyen. Mais de nombreuses caractéristiques architecturales sont basées sur des statistiques et, selon les conditions initiales, peuvent conduire à des durées d'exécution très différentes. Cela inclut principalement les caches et les prédicteurs de branche. Il est normal d'avoir des variations d'environ 20 à 30% à l'exécution. Et nous avons fait des expériences sur les systèmes baremetal OSless et le même comportement.

Voici un programme qui mesure les temps avec le compteur d'horodatage (cycles). Deux fonctions simples peuvent être testées. L'un est juste zéro vecteur et le second est un ensemble de tests sur un vecteur aléatoire (mais toujours identique).

#include <stdio.h>
#include <stdlib.h>
#define N 1000000
#define TYPE int
#define ZERO 0

static unsigned long long start_timer() ;
static unsigned long long stop_timer() ;
static double dtime(long long debut, long long fin);


#ifdef __i386__
#  define RDTSC_DIRTY "%eax", "%ebx", "%ecx", "%edx"
#elif __x86_64__
#  define RDTSC_DIRTY "%rax", "%rbx", "%rcx", "%rdx"
#else
# error unknown platform
#endif


static inline unsigned long long start_timer() 
{ 
  unsigned int hi = 0, lo = 0; 

  asm volatile("cpuid\n\t"
           "rdtscp\n\t"
           "mov %%edx, %0\n\t"
           "mov %%eax, %1\n\t" 
           : "=r" (hi), "=r" (lo)
           :: RDTSC_DIRTY);      
  unsigned long long that =   (unsigned long long)((lo) |
                           (unsigned long long)(hi)<<32);

  return that; 
} 

static inline unsigned long long stop_timer() 
{ 
  unsigned int hi = 0, lo = 0; 

  asm volatile("rdtscp\n\t"    
           "mov %%edx, %0\n\t" 
           "mov %%eax, %1\n\t" 
           "cpuid\n\t"     
           : "=r" (hi), "=r" (lo)
           :: RDTSC_DIRTY);      
  unsigned long long that =   (unsigned long long)((lo) |
                           (unsigned long long)(hi)<<32);

  return that; 
} 

static inline double dtime(long long start, long long end)
{
  return (double) (end - start) ;
}


TYPE BF[N] ;

long long start, end;
double benchtime;


void zero(){
  int i, j, m ;
  start=start_timer();
  for (i=0;i<N;i++)
    BF[i]=ZERO;
  benchtime=dtime(start, stop_timer());

  printf ("%g\n", benchtime);
}

void randtest(){
  int i, j, m ;
  srandom(100);
  for (i=0;i<N;i++)
    BF[i]=random();
  int count=0;
  start=start_timer();
  for (i=0;i<N;i++){
    if (BF[i]>RAND_MAX/2)
      count++;
  }
  benchtime=dtime(start, stop_timer());

  printf ("%g\n", benchtime);
}



void main()
{
  #ifdef ZEROTEST
  zero();
  #else
  randtest();
  #endif
} 

Voici les résultats:

suis @ Mandel: ~ / tmp / d $ cc -DZEROTEST heure.c; pour i dans 1 2 3 4 5 6 7 8 9 10; do ./a.out; fait

1.09084e + 07 1.14298e + 07 1.07197e + 07 1.26519e + 07 1.32742e + 07 1.37184e + 07 1.54689e + 07 1.36335e + 07 1.20818e + 07 1.12298e + 07

suis @ Mandel: ~ / tmp / d $ cc -DZEROTEST -O heure.c; pour i dans 1 2 3 4 5 6 7 8 9 10; do ./a.out; fait

4.30112e + 06 4.37242e + 06 4.28102e + 06 4.51831e + 06 4.45952e + 06 5.77813e + 06 6.33686e + 06 5.44415e + 06 5.67434e + 06 5.90118e + 06

suis @ Mandel: ~ / tmp / d $ cc time.c; pour i dans 1 2 3 4 5 6 7 8 9 10; do ./a.out; fait

2.4763e + 07 2.77489e + 07 2.78568e + 07 3.3762e + 07 3.56298e + 07 3.66709e + 07 3.22833e + 07 2.68651e + 07 2.88412e + 07 2.92287e + 07

suis @ Mandel: ~ / tmp / d $ cc -O time.c; pour i dans 1 2 3 4 5 6 7 8 9 10; do ./a.out; fait

1.00543e + 06 1.15819e + 06 1.00544e + 06 2.74409e + 06 1.17561e + 06 1.40751e + 06 2.41898e + 06 1.65623e + 06 2.19502e + 06 1.59414e + 06

Comme vous pouvez le voir, il est courant d'avoir au moins 30% de variation dans le temps, mais lorsque les prédicteurs de branche sont concernés, cela peut être beaucoup plus grand. Et cela se produit dans un code optimisé ou non optimisé.

Vous ne pouvez pas considérer que l'exécution est quelque chose de déterministe dans les architectures modernes. Il existe des variations dues aux choix de conception architecturale qui sont au moins aussi importants que les effets du système d'exploitation. Et c'est une difficulté majeure en temps réel.


0 commentaires