#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <unistd.h>

#define NB		50		/* nombre d'itérations (deprecated) */
#define SEC		1000000	/* 1 seconde, exprimée en micro secondes */

/* Typedef for a 64-bit wide unsigned int */
typedef struct
{
   unsigned long low;
   unsigned long high;
} UINT64;

/* Read Timer Stamp Counter */
unsigned long long rdtsc(void)
{
   unsigned long long x;

   __asm__ volatile(".byte 0x0f,0x31" : "=A" (x));

   return x;
}

/* On lit le Time Stamp Counter avant et après un
 * intervalle de temps à déterminer, et on en déduit
 * la fréquence du CPU.
 *
 * Note: la lecture de TSC est implémentée dans le kernel,
 * dans time.c De plus, le noyau prends en compte le
 * fabriquant du proc (ce prog ne devrait bien fonctionner
 * qu'avec des pentiums et consorts).
 *
 * La comparaison n'est effectuée que sur la partie basse
 * du TSC à l'heure actuelle, cela satisfaisant nos besoins.
 *
 * usage: argument = temps à attendre en milli secondes 
 */
int main(int argc, char **argv) {
  /* int i; */
  int time;
  unsigned long long before, after;
  double freq;

  if( argc != 2 || (time = atoi(argv[1])) == 0) {
    fprintf(stderr, "usage: %s <temps en milli secs>\n", basename(argv[0]));
    exit(1);
  }

  /* première lecture TSC */
  before = rdtsc();
  printf("TSC: %llu\n", before);

  /* on attend comme on a dit (usleep attend en micro secondes) */
  usleep(1000*time);

  /* re-lecture TSC */
  after = rdtsc();
  printf("TSC: %llu\n", after);

  /* on déduit de tout ca la fréquence du CPU * puis on l'affiche.
   * Plus on attend et plus on est précis.
   * On peut noter qu'une attente inférieure à la seconde
   * donne des résultats très éloignés de la réalité !
   */

  freq = ((double)(after - before)) / (1000.0*time);

  printf("Fréquence nominale CPU: %g MHz.\n", freq);
	
  /* deprecated:
   * boucle de lecture du TSC et affichage de la partie low du résultat.
   *
   for(i=0; i<NB;i++) {
   printf("TSC = %lu\n",rdtsc());
   }
   */

  return 0;
}
