void my_timer_init()

in mysys/my_rdtsc.c [493:793]


void my_timer_init(MY_TIMER_INFO *mti)
{
  ulonglong (*best_timer)(void);
  ulonglong best_timer_overhead;
  ulonglong time1, time2;
  int i;

  /* cycles */
  mti->cycles.frequency= 1000000000;
#if defined(__GNUC__) && defined(__i386__)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86;
#elif defined(__SUNPRO_C) && defined(__i386)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86;
#elif defined(__GNUC__) && defined(__x86_64__)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86_64;
#elif defined(HAVE_ASM_MSR_H) && defined(HAVE_RDTSCLL)
  mti->cycles.routine= MY_TIMER_ROUTINE_RDTSCLL;
#elif defined(_WIN32) && defined(_M_IX86)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_X86_WIN;
#elif defined(_WIN64) && defined(_M_X64)
  mti->cycles.routine= MY_TIMER_ROUTINE_RDTSC;
#elif defined(__INTEL_COMPILER) && defined(__ia64__) && defined(HAVE_IA64INTRIN_H)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_IA64;
#elif defined(__GNUC__) && defined(__ia64__)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_IA64;
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (defined(__64BIT__) || defined(_ARCH_PPC64))
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_PPC64;
#elif defined(__GNUC__) && (defined(__powerpc__) || defined(__POWERPC__) || (defined(_POWER) && defined(_AIX52))) && (!defined(__64BIT__) && !defined(_ARCH_PPC64))
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_PPC;
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__sparcv9) && defined(_LP64) && !defined(__SunOS_5_7)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC64;
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(_ILP32) && !defined(__SunOS_5_7)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_SPARC32;
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__i386) && defined(_ILP32)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_I386;
#elif (defined(__SUNPRO_CC) || defined(__SUNPRO_C)) && defined(__x86_64) && defined(_LP64)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_SUNPRO_X86_64;
#elif defined(__GNUC__) && defined(__sparcv9) && defined(_LP64) && (__GNUC__>2)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_GCC_SPARC64;
#elif defined(__GNUC__) && defined(__sparc__) && !defined(_LP64) && (__GNUC__>2)
  mti->cycles.routine= MY_TIMER_ROUTINE_ASM_GCC_SPARC32;
#elif defined(__sgi) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_SGI_CYCLE)
  mti->cycles.routine= MY_TIMER_ROUTINE_SGI_CYCLE;
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
  mti->cycles.routine= MY_TIMER_ROUTINE_GETHRTIME;
#else
  mti->cycles.routine= 0;
#endif

  if (!mti->cycles.routine || !my_timer_cycles())
  {
    mti->cycles.routine= 0;
    mti->cycles.resolution= 0;
    mti->cycles.frequency= 0;
    mti->cycles.overhead= 0;
  }

  /* nanoseconds */
  mti->nanoseconds.frequency=  1000000000; /* initial assumption */
#if defined(HAVE_READ_REAL_TIME)
  mti->nanoseconds.routine= MY_TIMER_ROUTINE_READ_REAL_TIME;
#elif defined(HAVE_SYS_TIMES_H) && defined(HAVE_GETHRTIME)
  mti->nanoseconds.routine= MY_TIMER_ROUTINE_GETHRTIME;
#elif defined(HAVE_CLOCK_GETTIME)
  mti->nanoseconds.routine= MY_TIMER_ROUTINE_CLOCK_GETTIME;
#elif defined(__APPLE__) && defined(__MACH__)
  mti->nanoseconds.routine= MY_TIMER_ROUTINE_MACH_ABSOLUTE_TIME;
#else
  mti->nanoseconds.routine= 0;
#endif
  if (!mti->nanoseconds.routine || !my_timer_nanoseconds())
  {
    mti->nanoseconds.routine= 0;
    mti->nanoseconds.resolution= 0;
    mti->nanoseconds.frequency= 0;
    mti->nanoseconds.overhead= 0;
  }

  /* microseconds */
  mti->microseconds.frequency= 1000000; /* initial assumption */
#if defined(HAVE_GETTIMEOFDAY)
   mti->microseconds.routine= MY_TIMER_ROUTINE_GETTIMEOFDAY;
#elif defined(_WIN32)
  {
    LARGE_INTEGER li;
    /* Windows: typical frequency = 3579545, actually 1/3 microsecond. */
    if (!QueryPerformanceFrequency(&li))
      mti->microseconds.routine= 0;
    else
    {
      mti->microseconds.frequency= li.QuadPart;
      mti->microseconds.routine= MY_TIMER_ROUTINE_QUERYPERFORMANCECOUNTER;
    }
  }
#else
  mti->microseconds.routine= 0;
#endif
  if (!mti->microseconds.routine || !my_timer_microseconds())
  {
    mti->microseconds.routine= 0;
    mti->microseconds.resolution= 0;
    mti->microseconds.frequency= 0;
    mti->microseconds.overhead= 0;
  }

  /* milliseconds */
  mti->milliseconds.frequency= 1000; /* initial assumption */
#if defined(HAVE_SYS_TIMEB_H) && defined(HAVE_FTIME)
  mti->milliseconds.routine= MY_TIMER_ROUTINE_FTIME;
#elif defined(_WIN32)
  mti->milliseconds.routine= MY_TIMER_ROUTINE_GETSYSTEMTIMEASFILETIME;
#elif defined(HAVE_TIME)
  mti->milliseconds.routine= MY_TIMER_ROUTINE_TIME;
#else
  mti->milliseconds.routine= 0;
#endif
  if (!mti->milliseconds.routine || !my_timer_milliseconds())
  {
    mti->milliseconds.routine= 0;
    mti->milliseconds.resolution= 0;
    mti->milliseconds.frequency= 0;
    mti->milliseconds.overhead= 0;
  }

  /* ticks */
  mti->ticks.frequency= 100; /* permanent assumption */
#if defined(HAVE_SYS_TIMES_H) && defined(HAVE_TIMES)
  mti->ticks.routine= MY_TIMER_ROUTINE_TIMES;
#elif defined(_WIN32)
  mti->ticks.routine= MY_TIMER_ROUTINE_GETTICKCOUNT;
#else
  mti->ticks.routine= 0;
#endif
  if (!mti->ticks.routine || !my_timer_ticks())
  {
    mti->ticks.routine= 0;
    mti->ticks.resolution= 0;
    mti->ticks.frequency= 0;
    mti->ticks.overhead= 0;
  }

  /*
    Calculate overhead in terms of the timer that
    gives the best resolution: cycles or nanoseconds.
    I doubt it ever will be as bad as microseconds.
  */
  if (mti->cycles.routine)
    best_timer= &my_timer_cycles;
  else
  {
    if (mti->nanoseconds.routine)
    {
      best_timer= &my_timer_nanoseconds;
    }
    else
      best_timer= &my_timer_microseconds;
  }

  /* best_timer_overhead = least of 20 calculations */
  for (i= 0, best_timer_overhead= 1000000000; i < 20; ++i)
  {
    time1= best_timer();
    time2= best_timer() - time1;
    if (best_timer_overhead > time2)
      best_timer_overhead= time2;
  }
  if (mti->cycles.routine)
    my_timer_init_overhead(&mti->cycles.overhead,
                           best_timer,
                           &my_timer_cycles,
                           best_timer_overhead);
  if (mti->nanoseconds.routine)
    my_timer_init_overhead(&mti->nanoseconds.overhead,
                           best_timer,
                           &my_timer_nanoseconds,
                           best_timer_overhead);
  if (mti->microseconds.routine)
    my_timer_init_overhead(&mti->microseconds.overhead,
                           best_timer,
                           &my_timer_microseconds,
                           best_timer_overhead);
  if (mti->milliseconds.routine)
    my_timer_init_overhead(&mti->milliseconds.overhead,
                           best_timer,
                           &my_timer_milliseconds,
                           best_timer_overhead);
  if (mti->ticks.routine)
    my_timer_init_overhead(&mti->ticks.overhead,
                           best_timer,
                           &my_timer_ticks,
                           best_timer_overhead);

/*
  Calculate resolution for nanoseconds or microseconds
  or milliseconds, by seeing if it's always divisible
  by 1000, and by noticing how much jumping occurs.
  For ticks, just assume the resolution is 1.
*/
  if (mti->cycles.routine)
    mti->cycles.resolution= 1;
  if (mti->nanoseconds.routine)
    mti->nanoseconds.resolution=
    my_timer_init_resolution(&my_timer_nanoseconds, 20000);
  if (mti->microseconds.routine)
    mti->microseconds.resolution=
    my_timer_init_resolution(&my_timer_microseconds, 20);
  if (mti->milliseconds.routine)
  {
    if (mti->milliseconds.routine == MY_TIMER_ROUTINE_TIME)
      mti->milliseconds.resolution= 1000;
    else
      mti->milliseconds.resolution=
      my_timer_init_resolution(&my_timer_milliseconds, 0);
  }
  if (mti->ticks.routine)
    mti->ticks.resolution= 1;

/*
  Calculate cycles frequency,
  if we have both a cycles routine and a microseconds routine.
  In tests, this usually results in a figure within 2% of
  what "cat /proc/cpuinfo" says.
  If the microseconds routine is QueryPerformanceCounter
  (i.e. it's Windows), and the microseconds frequency is >
  500,000,000 (i.e. it's Windows Server so it uses RDTSC)
  and the microseconds resolution is > 100 (i.e. dreadful),
  then calculate cycles frequency = microseconds frequency.
*/
  if (mti->cycles.routine
  &&  mti->microseconds.routine)
  {
    if (mti->microseconds.routine ==
    MY_TIMER_ROUTINE_QUERYPERFORMANCECOUNTER
    &&  mti->microseconds.frequency > 500000000
    &&  mti->microseconds.resolution > 100)
      mti->cycles.frequency= mti->microseconds.frequency;
    else
    {
      ulonglong time1, time2;
      time1= my_timer_init_frequency(mti);
      /* Repeat once in case there was an interruption. */
      time2= my_timer_init_frequency(mti);
      if (time1 < time2) mti->cycles.frequency= time1;
      else mti->cycles.frequency= time2;
    }
  }

/*
  Calculate milliseconds frequency =
  (cycles-frequency/#-of-cycles) * #-of-milliseconds,
  if we have both a milliseconds routine and a cycles
  routine.
  This will be inaccurate if milliseconds resolution > 1.
  This is probably only useful when testing new platforms.
*/
  if (mti->milliseconds.routine
  &&  mti->milliseconds.resolution < 1000
  &&  mti->microseconds.routine
  &&  mti->cycles.routine)
  {
    int i;
    ulonglong time1, time2, time3, time4;
    time1= my_timer_cycles();
    time2= my_timer_milliseconds();
    time3= time2; /* Avoids a Microsoft/IBM compiler warning */
    for (i= 0; i < MY_TIMER_ITERATIONS * 1000; ++i)
    {
      time3= my_timer_milliseconds();
      if (time3 - time2 > 10) break;
    }
    time4= my_timer_cycles();
    mti->milliseconds.frequency=
    (mti->cycles.frequency * (time3 - time2)) / (time4 - time1);
  }

/*
  Calculate ticks.frequency =
  (cycles-frequency/#-of-cycles * #-of-ticks,
  if we have both a ticks routine and a cycles
  routine,
  This is probably only useful when testing new platforms.
*/
  if (mti->ticks.routine
  &&  mti->microseconds.routine
  &&  mti->cycles.routine)
  {
    int i;
    ulonglong time1, time2, time3, time4;
    time1= my_timer_cycles();
    time2= my_timer_ticks();
    time3= time2; /* Avoids a Microsoft/IBM compiler warning */
    for (i= 0; i < MY_TIMER_ITERATIONS * 1000; ++i)
    {
      time3= my_timer_ticks();
      if (time3 - time2 > 10) break;
    }
    time4= my_timer_cycles();
    mti->ticks.frequency=
    (mti->cycles.frequency * (time3 - time2)) / (time4 - time1);
  }
}