Como medir tempo de execução de códigos em C
UFABC - MCZA020-13 - Programação Paralela


Baixe aqui o arquivo completo.

/*
 * Emilio Francesquini <e.francesquini@ufabc.edu.br>
 * 2018-10-01
 */

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <time.h>
#include <sys/time.h>
#include <x86intrin.h>

#define MICRO ((unsigned long) 1000000)
#define NANOS ((unsigned long)1000000000)
#define ITERS 300000000
long int temp = 0;

void foo () {
  for (int i = 0; i< ITERS; i++)
    temp+=temp;
}

int main() {

  printf("---------------------------------------\n");
  printf("gettimeofday()\n");
  struct timeval before, after;
  time_t         elapsedUs;
  gettimeofday(&before, NULL);
  foo();
  gettimeofday(&after, NULL);
  elapsedUs = after.tv_usec - before.tv_usec + (after.tv_sec - before.tv_sec) * MICRO;
  printf("Tempo total: %lu us - %lf s - Resolução: %lu ns\n",  elapsedUs, (double)elapsedUs/MICRO, NANOS/MICRO);


  /*===============================================
    ===============================================
    ===============================================*/

  printf("---------------------------------------\n");
  printf("clock()\n");
  clock_t start = clock();// Overflow em 72 minutos em máquinas 32 bits!
  foo();
  double elapsedTime = (double)(clock() - start) / CLOCKS_PER_SEC;
  printf ("Tempo total: %lf Resolução: %ld ns\n", elapsedTime, NANOS/CLOCKS_PER_SEC);

  /*===============================================
    ===============================================
    ===============================================*/

  printf("---------------------------------------\n");
  printf("clock_get_time()\n");
  uint64_t diff;
  struct timespec tick, tock;
  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tick);
  foo();
  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tock);
  diff = NANOS * (tock.tv_sec - tick.tv_sec) + tock.tv_nsec - tick.tv_nsec;
  printf("Tempo total: %" PRIu64 " ns - %lf s\n", diff, (double)diff/NANOS);

  /* Tipos de relógios. Veja: man clock_gettime

     CLOCK_REALTIME
     System-wide clock that  measures  real  (i.e.,  wall-clock)  time.

     CLOCK_REALTIME_COARSE (since Linux 2.6.32; Linux-specific)
     A  faster  but  less precise version of CLOCK_REALTIME.

     CLOCK_MONOTONIC
     Clock  that  cannot  be set and represents monotonic time since some unspecified starting
     point.

     CLOCK_MONOTONIC_COARSE (since Linux 2.6.32; Linux-specific)
     A faster but less precise version of CLOCK_MONOTONIC.  Use when you need very  fast,  but
     not fine-grained timestamps.

     CLOCK_MONOTONIC_RAW (since Linux 2.6.28; Linux-specific)
     Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time that is  not
     subject to NTP adjustments or the incremental adjustments performed by adjtime(3).

     CLOCK_BOOTTIME (since Linux 2.6.39; Linux-specific)
     Identical  to  CLOCK_MONOTONIC,  except it also includes any time that the system is sus‐
     pended.

     CLOCK_PROCESS_CPUTIME_ID (since Linux 2.6.12)
     Per-process CPU-time clock (measures CPU time consumed by all threads in the process).

     CLOCK_THREAD_CPUTIME_ID (since Linux 2.6.12)
     Thread-specific CPU-time clock.
  */

  struct timespec res;
  clock_getres(CLOCK_REALTIME, &res);
  printf("Resolução CLOCK_REALTIME: %" PRIu64 " ns\n",
         (uint64_t) NANOS * res.tv_sec + res.tv_nsec);
  clock_getres(CLOCK_REALTIME_COARSE, &res);
  printf("Resolução CLOCK_REALTIME_COARSE: %" PRIu64 " ns\n",
         (uint64_t) NANOS * res.tv_sec + res.tv_nsec);
  clock_getres(CLOCK_MONOTONIC, &res);
  printf("Resolução CLOCK_MONOTONIC: %" PRIu64 " ns\n",
         (uint64_t) NANOS * res.tv_sec + res.tv_nsec);
  clock_getres(CLOCK_MONOTONIC_COARSE, &res);
  printf("Resolução CLOCK_MONOTONIC_COARSE: %" PRIu64 " ns\n",
         (uint64_t) NANOS * res.tv_sec + res.tv_nsec);
  clock_getres(CLOCK_PROCESS_CPUTIME_ID, &res);
  printf("Resolução CLOCK_PROCESS_CPUTIME_ID: %" PRIu64 " ns\n",
         (uint64_t) NANOS * res.tv_sec + res.tv_nsec);
  clock_getres(CLOCK_THREAD_CPUTIME_ID, &res);
  printf("Resolução CLOCK_THREAD_CPUTIME_ID: %" PRIu64 " ns\n",
         (uint64_t) NANOS * res.tv_sec + res.tv_nsec);
  clock_getres(CLOCK_BOOTTIME, &res);
  printf("Resolução CLOCK_BOOTTIME: %" PRIu64 " ns\n",
         (uint64_t) NANOS * res.tv_sec + res.tv_nsec);


   /*===============================================
    ===============================================
    ===============================================*/

  /*
    Para info apenas. Complicado utilizar pois existem diversos
    problemas como:
    - Não tem suporte em todas as arquiteturas
    - Não tem suporte em todos os compiladores
    - Reordenamento de instruções do processador
    - Variações de frequência
    - Não mede em tempo, mas em ciclos de clock (desconhecido e
      variável)
      - A menos que o processador suporte "invariant TSC"
   */
  printf("---------------------------------------\n");
  printf("__rdtsc()\n");
  uint64_t tsc = __rdtsc();
  foo();
  uint64_t tsc2 = __rdtsc();
  uint64_t tscDiff = tsc2 - tsc;
  printf ("Tempo total: %" PRIu64 " ciclos - Supondo 2.9GHz: %lf s\n", tscDiff, (double)tscDiff/2900000000.0);

  printf("---------------------------------------\n");
}

Autor: Emilio Francesquini

Created: 2019-03-10 dom 18:07