Blame tune/freq.c

Packit 5c3484
/* CPU frequency determination.
Packit 5c3484
Packit 5c3484
Copyright 1999-2004 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* Currently we don't get a CPU frequency on the following systems,
Packit 5c3484
Packit 5c3484
   alphaev5-cray-unicosmk2.0.6.X
Packit 5c3484
       times() has been seen at 13.33 ns (75 MHz), which is probably not the
Packit 5c3484
       cpu frequency.  Measuring the cycle counter against that would be
Packit 5c3484
       possible though.  But currently we don't use the cycle counter due to
Packit 5c3484
       unicos having int==8bytes where tune/alpha.asm assumes int==4bytes.
Packit 5c3484
Packit 5c3484
   m68040-unknown-netbsd1.4.1
Packit 5c3484
       Not sure if the system even knows the cpu frequency.  There's no
Packit 5c3484
       cycle counter to measure, though we could perhaps make a loop taking
Packit 5c3484
       a known number of cycles and measure that.
Packit 5c3484
Packit 5c3484
   power-ibm-aix4.2.1.0
Packit 5c3484
   power2-ibm-aix4.3.1.0
Packit 5c3484
   powerpc604-ibm-aix4.3.1.0
Packit 5c3484
   powerpc604-ibm-aix4.3.3.0
Packit 5c3484
   powerpc630-ibm-aix4.3.3.0
Packit 5c3484
   powerpc-unknown-netbsd1.6
Packit 5c3484
       Don't know where any info hides on these.  mftb is not related to the
Packit 5c3484
       cpu frequency so doesn't help.
Packit 5c3484
Packit 5c3484
   sparc-unknown-linux-gnu [maybe]
Packit 5c3484
       Don't know where any info hides on this.
Packit 5c3484
Packit 5c3484
   t90-cray-unicos10.0.X
Packit 5c3484
       The times() call seems to be for instance 2.22 nanoseconds, which
Packit 5c3484
       might be the cpu frequency (450 mhz), but need to confirm that.
Packit 5c3484
Packit 5c3484
*/
Packit 5c3484
Packit 5c3484
#include "config.h"
Packit 5c3484
Packit 5c3484
#if HAVE_INVENT_H
Packit 5c3484
#include <invent.h> /* for IRIX invent_cpuinfo_t */
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#include <stdio.h>
Packit 5c3484
#include <stdlib.h> /* for getenv, qsort */
Packit 5c3484
#include <string.h> /* for memcmp */
Packit 5c3484
Packit 5c3484
#if HAVE_UNISTD_H
Packit 5c3484
#include <unistd.h> /* for sysconf */
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#include <sys/types.h>
Packit 5c3484
Packit 5c3484
#if HAVE_SYS_ATTRIBUTES_H
Packit 5c3484
#include <sys/attributes.h>   /* for IRIX attr_get(), needs sys/types.h */
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if HAVE_SYS_IOGRAPH_H
Packit 5c3484
#include <sys/iograph.h>      /* for IRIX INFO_LBL_DETAIL_INVENT */
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if HAVE_SYS_PARAM_H     /* for constants needed by NetBSD <sys/sysctl.h> */
Packit 5c3484
#include <sys/param.h>   /* and needed by HPUX <sys/pstat.h> */
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if HAVE_SYS_PSTAT_H
Packit 5c3484
#include <sys/pstat.h>   /* for HPUX pstat_getprocessor() */
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if HAVE_SYS_SYSCTL_H
Packit 5c3484
#include <sys/sysctl.h>  /* for sysctlbyname() */
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if TIME_WITH_SYS_TIME
Packit 5c3484
# include <sys/time.h>  /* for struct timeval */
Packit 5c3484
# include <time.h>
Packit 5c3484
#else
Packit 5c3484
# if HAVE_SYS_TIME_H
Packit 5c3484
#  include <sys/time.h>
Packit 5c3484
# else
Packit 5c3484
#  include <time.h>
Packit 5c3484
# endif
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if HAVE_SYS_RESOURCE_H
Packit 5c3484
#include <sys/resource.h>  /* for struct rusage */
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if HAVE_SYS_PROCESSOR_H
Packit 5c3484
#include <sys/processor.h>  /* for solaris processor_info_t */
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
/* On AIX 5.1 with gcc 2.9-aix51-020209 in -maix64 mode, <sys/sysinfo.h>
Packit 5c3484
   gets an error about "fill" in "struct cpuinfo" having a negative size,
Packit 5c3484
   apparently due to __64BIT_KERNEL not being defined because _KERNEL is not
Packit 5c3484
   defined.  Avoid this file if we don't actually need it, which we don't on
Packit 5c3484
   AIX since there's no getsysinfo there.  */
Packit 5c3484
#if HAVE_SYS_SYSINFO_H && HAVE_GETSYSINFO
Packit 5c3484
#include <sys/sysinfo.h>  /* for OSF getsysinfo */
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if HAVE_MACHINE_HAL_SYSINFO_H
Packit 5c3484
#include <machine/hal_sysinfo.h>  /* for OSF GSI_CPU_INFO, struct cpu_info */
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
/* Remove definitions from NetBSD <sys/param.h>, to avoid conflicts with
Packit 5c3484
   gmp-impl.h. */
Packit 5c3484
#ifdef MIN
Packit 5c3484
#undef MIN
Packit 5c3484
#endif
Packit 5c3484
#ifdef MAX
Packit 5c3484
#undef MAX
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
Packit 5c3484
#include "speed.h"
Packit 5c3484
Packit 5c3484
Packit 5c3484
#define HELP(str)                       \
Packit 5c3484
  if (help)                             \
Packit 5c3484
    {                                   \
Packit 5c3484
      printf ("    - %s\n", str);       \
Packit 5c3484
      return 0;                         \
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* GMP_CPU_FREQUENCY environment variable.  Should be in Hertz and can be
Packit 5c3484
   floating point, for example "450e6". */
Packit 5c3484
static int
Packit 5c3484
freq_environment (int help)
Packit 5c3484
{
Packit 5c3484
  char  *e;
Packit 5c3484
Packit 5c3484
  HELP ("environment variable GMP_CPU_FREQUENCY (in Hertz)");
Packit 5c3484
Packit 5c3484
  e = getenv ("GMP_CPU_FREQUENCY");
Packit 5c3484
  if (e == NULL)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  speed_cycletime = 1.0 / atof (e);
Packit 5c3484
Packit 5c3484
  if (speed_option_verbose)
Packit 5c3484
    printf ("Using GMP_CPU_FREQUENCY %.2f for cycle time %.3g\n",
Packit 5c3484
            atof (e), speed_cycletime);
Packit 5c3484
Packit 5c3484
  return 1;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* getsysinfo is available on OSF, or 4.0 and up at least.
Packit 5c3484
   The man page (on 4.0) suggests a 0 return indicates information not
Packit 5c3484
   available, but that seems to be the normal return for GSI_CPU_INFO.  */
Packit 5c3484
static int
Packit 5c3484
freq_getsysinfo (int help)
Packit 5c3484
{
Packit 5c3484
#if HAVE_GETSYSINFO
Packit 5c3484
  struct cpu_info  c;
Packit 5c3484
  int              start;
Packit 5c3484
Packit 5c3484
  HELP ("getsysinfo() GSI_CPU_INFO");
Packit 5c3484
Packit 5c3484
  start = 0;
Packit 5c3484
  if (getsysinfo (GSI_CPU_INFO, (caddr_t) &c, sizeof (c),
Packit 5c3484
                  &start, NULL, NULL) != -1)
Packit 5c3484
    {
Packit 5c3484
      speed_cycletime = 1e-6 / (double) c.mhz;
Packit 5c3484
      if (speed_option_verbose)
Packit 5c3484
        printf ("Using getsysinfo() GSI_CPU_INFO %u for cycle time %.3g\n",
Packit 5c3484
                c.mhz, speed_cycletime);
Packit 5c3484
      return 1;
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
  return 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* In HPUX 10 and up, pstat_getprocessor() psp_iticksperclktick is the
Packit 5c3484
   number of CPU cycles (ie. the CR16 register) per CLK_TCK.  HPUX 9 doesn't
Packit 5c3484
   have that field in pst_processor though, and has no apparent
Packit 5c3484
   equivalent.  */
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_pstat_getprocessor (int help)
Packit 5c3484
{
Packit 5c3484
#if HAVE_PSTAT_GETPROCESSOR && HAVE_PSP_ITICKSPERCLKTICK
Packit 5c3484
  struct pst_processor  p;
Packit 5c3484
Packit 5c3484
  HELP ("pstat_getprocessor() psp_iticksperclktick");
Packit 5c3484
Packit 5c3484
  if (pstat_getprocessor (&p, sizeof(p), 1, 0) != -1)
Packit 5c3484
    {
Packit 5c3484
      long  c = clk_tck();
Packit 5c3484
      speed_cycletime = 1.0 / (c * p.psp_iticksperclktick);
Packit 5c3484
      if (speed_option_verbose)
Packit 5c3484
        printf ("Using pstat_getprocessor() psp_iticksperclktick %lu and clk_tck %ld for cycle time %.3g\n",
Packit 5c3484
                (unsigned long) p.psp_iticksperclktick, c,
Packit 5c3484
                speed_cycletime);
Packit 5c3484
      return 1;
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
  return 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* i386 FreeBSD 2.2.8 sysctlbyname machdep.i586_freq is in Hertz.
Packit 5c3484
   There's no obvious defines available to get this from plain sysctl.  */
Packit 5c3484
static int
Packit 5c3484
freq_sysctlbyname_i586_freq (int help)
Packit 5c3484
{
Packit 5c3484
#if HAVE_SYSCTLBYNAME
Packit 5c3484
  unsigned  val;
Packit 5c3484
  size_t    size;
Packit 5c3484
Packit 5c3484
  HELP ("sysctlbyname() machdep.i586_freq");
Packit 5c3484
Packit 5c3484
  size = sizeof(val);
Packit 5c3484
  if (sysctlbyname ("machdep.i586_freq", &val, &size, NULL, 0) == 0
Packit 5c3484
      && size == sizeof(val))
Packit 5c3484
    {
Packit 5c3484
      speed_cycletime = 1.0 / (double) val;
Packit 5c3484
      if (speed_option_verbose)
Packit 5c3484
        printf ("Using sysctlbyname() machdep.i586_freq %u for cycle time %.3g\n",
Packit 5c3484
                val, speed_cycletime);
Packit 5c3484
      return 1;
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
  return 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* i368 FreeBSD 3.3 sysctlbyname machdep.tsc_freq is in Hertz.
Packit 5c3484
   There's no obvious defines to get this from plain sysctl.  */
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_sysctlbyname_tsc_freq (int help)
Packit 5c3484
{
Packit 5c3484
#if HAVE_SYSCTLBYNAME
Packit 5c3484
  unsigned  val;
Packit 5c3484
  size_t    size;
Packit 5c3484
Packit 5c3484
  HELP ("sysctlbyname() machdep.tsc_freq");
Packit 5c3484
Packit 5c3484
  size = sizeof(val);
Packit 5c3484
  if (sysctlbyname ("machdep.tsc_freq", &val, &size, NULL, 0) == 0
Packit 5c3484
      && size == sizeof(val))
Packit 5c3484
    {
Packit 5c3484
      speed_cycletime = 1.0 / (double) val;
Packit 5c3484
      if (speed_option_verbose)
Packit 5c3484
        printf ("Using sysctlbyname() machdep.tsc_freq %u for cycle time %.3g\n",
Packit 5c3484
                val, speed_cycletime);
Packit 5c3484
      return 1;
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
  return 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* Apple powerpc Darwin 1.3 sysctl hw.cpufrequency is in hertz.  For some
Packit 5c3484
   reason only seems to be available from sysctl(), not sysctlbyname().  */
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_sysctl_hw_cpufrequency (int help)
Packit 5c3484
{
Packit 5c3484
#if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_CPU_FREQ)
Packit 5c3484
  int       mib[2];
Packit 5c3484
  unsigned  val;
Packit 5c3484
  size_t    size;
Packit 5c3484
Packit 5c3484
  HELP ("sysctl() hw.cpufrequency");
Packit 5c3484
Packit 5c3484
  mib[0] = CTL_HW;
Packit 5c3484
  mib[1] = HW_CPU_FREQ;
Packit 5c3484
  size = sizeof(val);
Packit 5c3484
  if (sysctl (mib, 2, &val, &size, NULL, 0) == 0)
Packit 5c3484
    {
Packit 5c3484
      speed_cycletime = 1.0 / (double) val;
Packit 5c3484
      if (speed_option_verbose)
Packit 5c3484
        printf ("Using sysctl() hw.cpufrequency %u for cycle time %.3g\n",
Packit 5c3484
                val, speed_cycletime);
Packit 5c3484
      return 1;
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
  return 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* The following ssyctl hw.model strings have been observed,
Packit 5c3484
Packit 5c3484
       Alpha FreeBSD 4.1:   Digital AlphaPC 164LX 599 MHz
Packit 5c3484
       NetBSD 1.4:          Digital AlphaPC 164LX 599 MHz
Packit 5c3484
       NetBSD 1.6.1:        CY7C601 @ 40 MHz, TMS390C602A FPU
Packit 5c3484
Packit 5c3484
   NetBSD 1.4 doesn't seem to have sysctlbyname, so sysctl() is used.  */
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_sysctl_hw_model (int help)
Packit 5c3484
{
Packit 5c3484
#if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_MODEL)
Packit 5c3484
  int       mib[2];
Packit 5c3484
  char      str[128];
Packit 5c3484
  unsigned  val;
Packit 5c3484
  size_t    size;
Packit 5c3484
  char      *p;
Packit 5c3484
  int       end;
Packit 5c3484
Packit 5c3484
  HELP ("sysctl() hw.model");
Packit 5c3484
Packit 5c3484
  mib[0] = CTL_HW;
Packit 5c3484
  mib[1] = HW_MODEL;
Packit 5c3484
  size = sizeof(str);
Packit 5c3484
  if (sysctl (mib, 2, str, &size, NULL, 0) == 0)
Packit 5c3484
    {
Packit 5c3484
      for (p = str; *p != '\0'; p++)
Packit 5c3484
        {
Packit 5c3484
          end = 0;
Packit 5c3484
          if (sscanf (p, "%u MHz%n", &val, &end) == 1 && end != 0)
Packit 5c3484
            {
Packit 5c3484
              speed_cycletime = 1e-6 / (double) val;
Packit 5c3484
              if (speed_option_verbose)
Packit 5c3484
                printf ("Using sysctl() hw.model %u for cycle time %.3g\n",
Packit 5c3484
                        val, speed_cycletime);
Packit 5c3484
              return 1;
Packit 5c3484
            }
Packit 5c3484
        }
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
  return 0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* /proc/cpuinfo for linux kernel.
Packit 5c3484
Packit 5c3484
   Linux doesn't seem to have any system call to get the CPU frequency, at
Packit 5c3484
   least not in 2.0.x or 2.2.x, so it's necessary to read /proc/cpuinfo.
Packit 5c3484
Packit 5c3484
   i386 2.0.36 - "bogomips" is the CPU frequency.
Packit 5c3484
Packit 5c3484
   i386 2.2.13 - has both "cpu MHz" and "bogomips", and it's "cpu MHz" which
Packit 5c3484
                 is the frequency.
Packit 5c3484
Packit 5c3484
   alpha 2.2.5 - "cycle frequency [Hz]" seems to be right, "BogoMIPS" is
Packit 5c3484
                 very slightly different.
Packit 5c3484
Packit 5c3484
   alpha 2.2.18pre21 - "cycle frequency [Hz]" is 0 on at least one system,
Packit 5c3484
                 "BogoMIPS" seems near enough.
Packit 5c3484
Packit 5c3484
   powerpc 2.2.19 - "clock" is the frequency, bogomips is something weird
Packit 5c3484
  */
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_proc_cpuinfo (int help)
Packit 5c3484
{
Packit 5c3484
  FILE    *fp;
Packit 5c3484
  char    buf[128];
Packit 5c3484
  double  val;
Packit 5c3484
  int     ret = 0;
Packit 5c3484
  int     end;
Packit 5c3484
Packit 5c3484
  HELP ("linux kernel /proc/cpuinfo file, cpu MHz or bogomips");
Packit 5c3484
Packit 5c3484
  if ((fp = fopen ("/proc/cpuinfo", "r")) != NULL)
Packit 5c3484
    {
Packit 5c3484
      while (fgets (buf, sizeof (buf), fp) != NULL)
Packit 5c3484
        {
Packit 5c3484
          if (sscanf (buf, "cycle frequency [Hz]    : %lf", &val) == 1
Packit 5c3484
              && val != 0.0)
Packit 5c3484
            {
Packit 5c3484
              speed_cycletime = 1.0 / val;
Packit 5c3484
              if (speed_option_verbose)
Packit 5c3484
                printf ("Using /proc/cpuinfo \"cycle frequency\" %.2f for cycle time %.3g\n", val, speed_cycletime);
Packit 5c3484
              ret = 1;
Packit 5c3484
              break;
Packit 5c3484
            }
Packit 5c3484
          if (sscanf (buf, "cpu MHz : %lf\n", &val) == 1)
Packit 5c3484
            {
Packit 5c3484
              speed_cycletime = 1e-6 / val;
Packit 5c3484
              if (speed_option_verbose)
Packit 5c3484
                printf ("Using /proc/cpuinfo \"cpu MHz\" %.2f for cycle time %.3g\n", val, speed_cycletime);
Packit 5c3484
              ret = 1;
Packit 5c3484
              break;
Packit 5c3484
            }
Packit 5c3484
          end = 0;
Packit 5c3484
          if (sscanf (buf, "clock : %lfMHz\n%n", &val, &end) == 1 && end != 0)
Packit 5c3484
            {
Packit 5c3484
              speed_cycletime = 1e-6 / val;
Packit 5c3484
              if (speed_option_verbose)
Packit 5c3484
                printf ("Using /proc/cpuinfo \"clock\" %.2f for cycle time %.3g\n", val, speed_cycletime);
Packit 5c3484
              ret = 1;
Packit 5c3484
              break;
Packit 5c3484
            }
Packit 5c3484
          if (sscanf (buf, "bogomips : %lf\n", &val) == 1
Packit 5c3484
              || sscanf (buf, "BogoMIPS : %lf\n", &val) == 1)
Packit 5c3484
            {
Packit 5c3484
              speed_cycletime = 1e-6 / val;
Packit 5c3484
              if (speed_option_verbose)
Packit 5c3484
                printf ("Using /proc/cpuinfo \"bogomips\" %.2f for cycle time %.3g\n", val, speed_cycletime);
Packit 5c3484
              ret = 1;
Packit 5c3484
              break;
Packit 5c3484
            }
Packit 5c3484
        }
Packit 5c3484
      fclose (fp);
Packit 5c3484
    }
Packit 5c3484
  return ret;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* /bin/sysinfo for SunOS 4.
Packit 5c3484
   Prints a line like: cpu0 is a "75 MHz TI,TMS390Z55" CPU */
Packit 5c3484
static int
Packit 5c3484
freq_sunos_sysinfo (int help)
Packit 5c3484
{
Packit 5c3484
  int     ret = 0;
Packit 5c3484
#if HAVE_POPEN
Packit 5c3484
  FILE    *fp;
Packit 5c3484
  char    buf[128];
Packit 5c3484
  double  val;
Packit 5c3484
  int     end;
Packit 5c3484
Packit 5c3484
  HELP ("SunOS /bin/sysinfo program output, cpu0");
Packit 5c3484
Packit 5c3484
  /* Error messages are sent to /dev/null in case /bin/sysinfo doesn't
Packit 5c3484
     exist.  The brackets are necessary for some shells. */
Packit 5c3484
  if ((fp = popen ("(/bin/sysinfo) 2>/dev/null", "r")) != NULL)
Packit 5c3484
    {
Packit 5c3484
      while (fgets (buf, sizeof (buf), fp) != NULL)
Packit 5c3484
        {
Packit 5c3484
          end = 0;
Packit 5c3484
          if (sscanf (buf, " cpu0 is a \"%lf MHz%n", &val, &end) == 1
Packit 5c3484
              && end != 0)
Packit 5c3484
            {
Packit 5c3484
              speed_cycletime = 1e-6 / val;
Packit 5c3484
              if (speed_option_verbose)
Packit 5c3484
                printf ("Using /bin/sysinfo \"cpu0 MHz\" %.2f for cycle time %.3g\n", val, speed_cycletime);
Packit 5c3484
              ret = 1;
Packit 5c3484
              break;
Packit 5c3484
            }
Packit 5c3484
        }
Packit 5c3484
      pclose (fp);
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
  return ret;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* "/etc/hw -r cpu" for SCO OpenUnix 8, printing a line like
Packit 5c3484
	The speed of the CPU is approximately 450MHz
Packit 5c3484
 */
Packit 5c3484
static int
Packit 5c3484
freq_sco_etchw (int help)
Packit 5c3484
{
Packit 5c3484
  int     ret = 0;
Packit 5c3484
#if HAVE_POPEN
Packit 5c3484
  FILE    *fp;
Packit 5c3484
  char    buf[128];
Packit 5c3484
  double  val;
Packit 5c3484
  int     end;
Packit 5c3484
Packit 5c3484
  HELP ("SCO /etc/hw program output");
Packit 5c3484
Packit 5c3484
  /* Error messages are sent to /dev/null in case /etc/hw doesn't exist.
Packit 5c3484
     The brackets are necessary for some shells. */
Packit 5c3484
  if ((fp = popen ("(/etc/hw -r cpu) 2>/dev/null", "r")) != NULL)
Packit 5c3484
    {
Packit 5c3484
      while (fgets (buf, sizeof (buf), fp) != NULL)
Packit 5c3484
        {
Packit 5c3484
          end = 0;
Packit 5c3484
          if (sscanf (buf, " The speed of the CPU is approximately %lfMHz%n",
Packit 5c3484
                      &val, &end) == 1 && end != 0)
Packit 5c3484
            {
Packit 5c3484
              speed_cycletime = 1e-6 / val;
Packit 5c3484
              if (speed_option_verbose)
Packit 5c3484
                printf ("Using /etc/hw %.2f MHz, for cycle time %.3g\n",
Packit 5c3484
                        val, speed_cycletime);
Packit 5c3484
              ret = 1;
Packit 5c3484
              break;
Packit 5c3484
            }
Packit 5c3484
        }
Packit 5c3484
      pclose (fp);
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
  return ret;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* attr_get("/hw/cpunum/0",INFO_LBL_DETAIL_INVENT) ic_cpu_info.cpufq for
Packit 5c3484
   IRIX 6.5.  Past versions don't have INFO_LBL_DETAIL_INVENT,
Packit 5c3484
   invent_cpuinfo_t, or /hw/cpunum/0.
Packit 5c3484
Packit 5c3484
   The same information is available from the "hinv -c processor" command,
Packit 5c3484
   but it seems better to make a system call where possible. */
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_attr_get_invent (int help)
Packit 5c3484
{
Packit 5c3484
  int     ret = 0;
Packit 5c3484
#if HAVE_ATTR_GET && HAVE_INVENT_H && defined (INFO_LBL_DETAIL_INVENT)
Packit 5c3484
  invent_cpuinfo_t  inv;
Packit 5c3484
  int               len, val;
Packit 5c3484
Packit 5c3484
  HELP ("attr_get(\"/hw/cpunum/0\") ic_cpu_info.cpufq");
Packit 5c3484
Packit 5c3484
  len = sizeof (inv);
Packit 5c3484
  if (attr_get ("/hw/cpunum/0", INFO_LBL_DETAIL_INVENT,
Packit 5c3484
                (char *) &inv, &len, 0) == 0
Packit 5c3484
      && len == sizeof (inv)
Packit 5c3484
      && inv.ic_gen.ig_invclass == INV_PROCESSOR)
Packit 5c3484
    {
Packit 5c3484
      val = inv.ic_cpu_info.cpufq;
Packit 5c3484
      speed_cycletime = 1e-6 / val;
Packit 5c3484
      if (speed_option_verbose)
Packit 5c3484
        printf ("Using attr_get(\"/hw/cpunum/0\") ic_cpu_info.cpufq %d MHz for cycle time %.3g\n", val, speed_cycletime);
Packit 5c3484
      ret = 1;
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
  return ret;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* FreeBSD on i386 gives a line like the following at bootup, and which can
Packit 5c3484
   be read back from /var/run/dmesg.boot.
Packit 5c3484
Packit 5c3484
       CPU: AMD Athlon(tm) Processor (755.29-MHz 686-class CPU)
Packit 5c3484
       CPU: Pentium 4 (1707.56-MHz 686-class CPU)
Packit 5c3484
       CPU: i486 DX4 (486-class CPU)
Packit 5c3484
Packit 5c3484
   This is useful on FreeBSD 4.x, where there's no sysctl machdep.tsc_freq
Packit 5c3484
   or machdep.i586_freq.
Packit 5c3484
Packit 5c3484
   It's better to use /var/run/dmesg.boot than to run /sbin/dmesg, since the
Packit 5c3484
   latter prints the current system message buffer, which is a limited size
Packit 5c3484
   and can wrap around if the system is up for a long time.  */
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_bsd_dmesg (int help)
Packit 5c3484
{
Packit 5c3484
  FILE    *fp;
Packit 5c3484
  char    buf[256], *p;
Packit 5c3484
  double  val;
Packit 5c3484
  int     ret = 0;
Packit 5c3484
  int     end;
Packit 5c3484
Packit 5c3484
  HELP ("BSD /var/run/dmesg.boot file");
Packit 5c3484
Packit 5c3484
  if ((fp = fopen ("/var/run/dmesg.boot", "r")) != NULL)
Packit 5c3484
    {
Packit 5c3484
      while (fgets (buf, sizeof (buf), fp) != NULL)
Packit 5c3484
        {
Packit 5c3484
          if (memcmp (buf, "CPU:", 4) == 0)
Packit 5c3484
            {
Packit 5c3484
              for (p = buf; *p != '\0'; p++)
Packit 5c3484
                {
Packit 5c3484
                  end = 0;
Packit 5c3484
                  if (sscanf (p, "(%lf-MHz%n", &val, &end) == 1 && end != 0)
Packit 5c3484
                    {
Packit 5c3484
                      speed_cycletime = 1e-6 / val;
Packit 5c3484
                      if (speed_option_verbose)
Packit 5c3484
                        printf ("Using /var/run/dmesg.boot CPU: %.2f MHz for cycle time %.3g\n", val, speed_cycletime);
Packit 5c3484
                      ret = 1;
Packit 5c3484
                      break;
Packit 5c3484
                    }
Packit 5c3484
                }
Packit 5c3484
            }
Packit 5c3484
        }
Packit 5c3484
      fclose (fp);
Packit 5c3484
    }
Packit 5c3484
  return ret;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* "hinv -c processor" for IRIX.  The following lines have been seen,
Packit 5c3484
Packit 5c3484
              1 150 MHZ IP20 Processor
Packit 5c3484
              2 195 MHZ IP27 Processors
Packit 5c3484
              Processor 0: 500 MHZ IP35
Packit 5c3484
Packit 5c3484
   This information is available from attr_get() on IRIX 6.5 (see above),
Packit 5c3484
   but on IRIX 6.2 it's not clear where to look, so fall back on
Packit 5c3484
   parsing.  */
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_irix_hinv (int help)
Packit 5c3484
{
Packit 5c3484
  int     ret = 0;
Packit 5c3484
#if HAVE_POPEN
Packit 5c3484
  FILE    *fp;
Packit 5c3484
  char    buf[128];
Packit 5c3484
  double  val;
Packit 5c3484
  int     nproc, end;
Packit 5c3484
Packit 5c3484
  HELP ("IRIX \"hinv -c processor\" output");
Packit 5c3484
Packit 5c3484
  /* Error messages are sent to /dev/null in case hinv doesn't exist.  The
Packit 5c3484
     brackets are necessary for some shells. */
Packit 5c3484
  if ((fp = popen ("(hinv -c processor) 2>/dev/null", "r")) != NULL)
Packit 5c3484
    {
Packit 5c3484
      while (fgets (buf, sizeof (buf), fp) != NULL)
Packit 5c3484
        {
Packit 5c3484
          end = 0;
Packit 5c3484
          if (sscanf (buf, "Processor 0: %lf MHZ%n", &val, &end) == 1
Packit 5c3484
              && end != 0)
Packit 5c3484
            {
Packit 5c3484
            found:
Packit 5c3484
              speed_cycletime = 1e-6 / val;
Packit 5c3484
              if (speed_option_verbose)
Packit 5c3484
                printf ("Using hinv -c processor \"%.2f MHZ\" for cycle time %.3g\n", val, speed_cycletime);
Packit 5c3484
              ret = 1;
Packit 5c3484
              break;
Packit 5c3484
            }
Packit 5c3484
          end = 0;
Packit 5c3484
          if (sscanf (buf, "%d %lf MHZ%n", &nproc, &val, &end) == 2
Packit 5c3484
              && end != 0)
Packit 5c3484
            goto found;
Packit 5c3484
        }
Packit 5c3484
      pclose (fp);
Packit 5c3484
    }
Packit 5c3484
#endif
Packit 5c3484
  return ret;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* processor_info() for Solaris.  "psrinfo" is the command-line interface to
Packit 5c3484
   this.  "prtconf -vp" gives similar information.
Packit 5c3484
Packit 5c3484
   Apple Darwin has a processor_info, but in an incompatible style.  It
Packit 5c3484
   doesn't have <sys/processor.h>, so test for that.  */
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_processor_info (int help)
Packit 5c3484
{
Packit 5c3484
#if HAVE_PROCESSOR_INFO && HAVE_SYS_PROCESSOR_H
Packit 5c3484
  processor_info_t  p;
Packit 5c3484
  int  i, n, mhz = 0;
Packit 5c3484
Packit 5c3484
  HELP ("processor_info() pi_clock");
Packit 5c3484
Packit 5c3484
  n = sysconf (_SC_NPROCESSORS_CONF);
Packit 5c3484
  for (i = 0; i < n; i++)
Packit 5c3484
    {
Packit 5c3484
      if (processor_info (i, &p) != 0)
Packit 5c3484
        continue;
Packit 5c3484
      if (p.pi_state != P_ONLINE)
Packit 5c3484
        continue;
Packit 5c3484
Packit 5c3484
      if (mhz != 0 && p.pi_clock != mhz)
Packit 5c3484
        {
Packit 5c3484
          fprintf (stderr,
Packit 5c3484
                   "freq_processor_info(): There's more than one CPU and they have different clock speeds\n");
Packit 5c3484
          return 0;
Packit 5c3484
        }
Packit 5c3484
Packit 5c3484
      mhz = p.pi_clock;
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  speed_cycletime = 1.0e-6 / (double) mhz;
Packit 5c3484
Packit 5c3484
  if (speed_option_verbose)
Packit 5c3484
    printf ("Using processor_info() %d mhz for cycle time %.3g\n",
Packit 5c3484
            mhz, speed_cycletime);
Packit 5c3484
  return 1;
Packit 5c3484
Packit 5c3484
#else
Packit 5c3484
  return 0;
Packit 5c3484
#endif
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
#if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY
Packit 5c3484
static double
Packit 5c3484
freq_measure_gettimeofday_one (void)
Packit 5c3484
{
Packit 5c3484
#define call_gettimeofday(t)   gettimeofday (&(t), NULL)
Packit 5c3484
#define timeval_tv_sec(t)      ((t).tv_sec)
Packit 5c3484
#define timeval_tv_usec(t)     ((t).tv_usec)
Packit 5c3484
  FREQ_MEASURE_ONE ("gettimeofday", struct timeval,
Packit 5c3484
                    call_gettimeofday, speed_cyclecounter,
Packit 5c3484
                    timeval_tv_sec, timeval_tv_usec);
Packit 5c3484
}
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
#if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE
Packit 5c3484
static double
Packit 5c3484
freq_measure_getrusage_one (void)
Packit 5c3484
{
Packit 5c3484
#define call_getrusage(t)   getrusage (0, &(t))
Packit 5c3484
#define rusage_tv_sec(t)    ((t).ru_utime.tv_sec)
Packit 5c3484
#define rusage_tv_usec(t)   ((t).ru_utime.tv_usec)
Packit 5c3484
  FREQ_MEASURE_ONE ("getrusage", struct rusage,
Packit 5c3484
                    call_getrusage, speed_cyclecounter,
Packit 5c3484
                    rusage_tv_sec, rusage_tv_usec);
Packit 5c3484
}
Packit 5c3484
#endif
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* MEASURE_MATCH is how many readings within MEASURE_TOLERANCE of each other
Packit 5c3484
   are required.  This must be at least 2.  */
Packit 5c3484
#define MEASURE_MAX_ATTEMPTS   20
Packit 5c3484
#define MEASURE_TOLERANCE      1.005  /* 0.5% */
Packit 5c3484
#define MEASURE_MATCH          3
Packit 5c3484
Packit 5c3484
double
Packit 5c3484
freq_measure (const char *name, double (*one) (void))
Packit 5c3484
{
Packit 5c3484
  double  t[MEASURE_MAX_ATTEMPTS];
Packit 5c3484
  int     i, j;
Packit 5c3484
Packit 5c3484
  for (i = 0; i < numberof (t); i++)
Packit 5c3484
    {
Packit 5c3484
      t[i] = (*one) ();
Packit 5c3484
Packit 5c3484
      qsort (t, i+1, sizeof(t[0]), (qsort_function_t) double_cmp_ptr);
Packit 5c3484
      if (speed_option_verbose >= 3)
Packit 5c3484
        for (j = 0; j <= i; j++)
Packit 5c3484
          printf ("   t[%d] is %.6g\n", j, t[j]);
Packit 5c3484
Packit 5c3484
      for (j = 0; j+MEASURE_MATCH-1 <= i; j++)
Packit 5c3484
        {
Packit 5c3484
          if (t[j+MEASURE_MATCH-1] <= t[j] * MEASURE_TOLERANCE)
Packit 5c3484
            {
Packit 5c3484
              /* use the average of the range found */
Packit 5c3484
                return (t[j+MEASURE_MATCH-1] + t[j]) / 2.0;
Packit 5c3484
            }
Packit 5c3484
        }
Packit 5c3484
    }
Packit 5c3484
  return -1.0;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_measure_getrusage (int help)
Packit 5c3484
{
Packit 5c3484
#if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE
Packit 5c3484
  double  cycletime;
Packit 5c3484
Packit 5c3484
  if (! getrusage_microseconds_p ())
Packit 5c3484
    return 0;
Packit 5c3484
  if (! cycles_works_p ())
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  HELP ("cycle counter measured with microsecond getrusage()");
Packit 5c3484
Packit 5c3484
  cycletime = freq_measure ("getrusage", freq_measure_getrusage_one);
Packit 5c3484
  if (cycletime == -1.0)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  speed_cycletime = cycletime;
Packit 5c3484
  if (speed_option_verbose)
Packit 5c3484
    printf ("Using getrusage() measured cycle counter %.4g (%.2f MHz)\n",
Packit 5c3484
            speed_cycletime, 1e-6/speed_cycletime);
Packit 5c3484
  return 1;
Packit 5c3484
Packit 5c3484
#else
Packit 5c3484
  return 0;
Packit 5c3484
#endif
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_measure_gettimeofday (int help)
Packit 5c3484
{
Packit 5c3484
#if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY
Packit 5c3484
  double  cycletime;
Packit 5c3484
Packit 5c3484
  if (! gettimeofday_microseconds_p ())
Packit 5c3484
    return 0;
Packit 5c3484
  if (! cycles_works_p ())
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  HELP ("cycle counter measured with microsecond gettimeofday()");
Packit 5c3484
Packit 5c3484
  cycletime = freq_measure ("gettimeofday", freq_measure_gettimeofday_one);
Packit 5c3484
  if (cycletime == -1.0)
Packit 5c3484
    return 0;
Packit 5c3484
Packit 5c3484
  speed_cycletime = cycletime;
Packit 5c3484
  if (speed_option_verbose)
Packit 5c3484
    printf ("Using gettimeofday() measured cycle counter %.4g (%.2f MHz)\n",
Packit 5c3484
            speed_cycletime, 1e-6/speed_cycletime);
Packit 5c3484
  return 1;
Packit 5c3484
#else
Packit 5c3484
  return 0;
Packit 5c3484
#endif
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
/* Each function returns 1 if it succeeds in setting speed_cycletime, or 0
Packit 5c3484
   if not.
Packit 5c3484
Packit 5c3484
   In general system call tests are first since they're fast, then file
Packit 5c3484
   tests, then tests running programs.  Necessary exceptions to this rule
Packit 5c3484
   are noted.  The measuring is last since it's time consuming, and rather
Packit 5c3484
   wasteful of cpu.  */
Packit 5c3484
Packit 5c3484
static int
Packit 5c3484
freq_all (int help)
Packit 5c3484
{
Packit 5c3484
  return
Packit 5c3484
    /* This should be first, so an environment variable can override
Packit 5c3484
       anything the system gives. */
Packit 5c3484
    freq_environment (help)
Packit 5c3484
Packit 5c3484
    || freq_attr_get_invent (help)
Packit 5c3484
    || freq_getsysinfo (help)
Packit 5c3484
    || freq_pstat_getprocessor (help)
Packit 5c3484
    || freq_sysctl_hw_model (help)
Packit 5c3484
    || freq_sysctl_hw_cpufrequency (help)
Packit 5c3484
    || freq_sysctlbyname_i586_freq (help)
Packit 5c3484
    || freq_sysctlbyname_tsc_freq (help)
Packit 5c3484
Packit 5c3484
    /* SCO openunix 8 puts a dummy pi_clock==16 in processor_info, so be
Packit 5c3484
       sure to check /etc/hw before that function. */
Packit 5c3484
    || freq_sco_etchw (help)
Packit 5c3484
Packit 5c3484
    || freq_processor_info (help)
Packit 5c3484
    || freq_proc_cpuinfo (help)
Packit 5c3484
    || freq_bsd_dmesg (help)
Packit 5c3484
    || freq_irix_hinv (help)
Packit 5c3484
    || freq_sunos_sysinfo (help)
Packit 5c3484
    || freq_measure_getrusage (help)
Packit 5c3484
    || freq_measure_gettimeofday (help);
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
speed_cycletime_init (void)
Packit 5c3484
{
Packit 5c3484
  static int  attempted = 0;
Packit 5c3484
Packit 5c3484
  if (attempted)
Packit 5c3484
    return;
Packit 5c3484
  attempted = 1;
Packit 5c3484
Packit 5c3484
  if (freq_all (0))
Packit 5c3484
    return;
Packit 5c3484
Packit 5c3484
  if (speed_option_verbose)
Packit 5c3484
    printf ("CPU frequency couldn't be determined\n");
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
Packit 5c3484
void
Packit 5c3484
speed_cycletime_fail (const char *str)
Packit 5c3484
{
Packit 5c3484
  fprintf (stderr, "Measuring with: %s\n", speed_time_string);
Packit 5c3484
  fprintf (stderr, "%s,\n", str);
Packit 5c3484
  fprintf (stderr, "but none of the following are available,\n");
Packit 5c3484
  freq_all (1);
Packit 5c3484
  abort ();
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
/* speed_time_init leaves speed_cycletime set to either 0.0 or 1.0 when the
Packit 5c3484
   CPU frequency is unknown.  0.0 is when the time base is in seconds, so
Packit 5c3484
   that's no good if cycles are wanted.  1.0 is when the time base is in
Packit 5c3484
   cycles, which conversely is no good if seconds are wanted.  */
Packit 5c3484
void
Packit 5c3484
speed_cycletime_need_cycles (void)
Packit 5c3484
{
Packit 5c3484
  speed_time_init ();
Packit 5c3484
  if (speed_cycletime == 0.0)
Packit 5c3484
    speed_cycletime_fail
Packit 5c3484
      ("Need to know CPU frequency to give times in cycles");
Packit 5c3484
}
Packit 5c3484
void
Packit 5c3484
speed_cycletime_need_seconds (void)
Packit 5c3484
{
Packit 5c3484
  speed_time_init ();
Packit 5c3484
  if (speed_cycletime == 1.0)
Packit 5c3484
    speed_cycletime_fail
Packit 5c3484
      ("Need to know CPU frequency to convert cycles to seconds");
Packit 5c3484
}