(root)/
gmp-6.3.0/
tune/
freq.c
       1  /* CPU frequency determination.
       2  
       3  Copyright 1999-2004 Free Software Foundation, Inc.
       4  
       5  This file is part of the GNU MP Library.
       6  
       7  The GNU MP Library is free software; you can redistribute it and/or modify
       8  it under the terms of either:
       9  
      10    * the GNU Lesser General Public License as published by the Free
      11      Software Foundation; either version 3 of the License, or (at your
      12      option) any later version.
      13  
      14  or
      15  
      16    * the GNU General Public License as published by the Free Software
      17      Foundation; either version 2 of the License, or (at your option) any
      18      later version.
      19  
      20  or both in parallel, as here.
      21  
      22  The GNU MP Library is distributed in the hope that it will be useful, but
      23  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      24  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      25  for more details.
      26  
      27  You should have received copies of the GNU General Public License and the
      28  GNU Lesser General Public License along with the GNU MP Library.  If not,
      29  see https://www.gnu.org/licenses/.  */
      30  
      31  
      32  /* Currently we don't get a CPU frequency on the following systems,
      33  
      34     alphaev5-cray-unicosmk2.0.6.X
      35         times() has been seen at 13.33 ns (75 MHz), which is probably not the
      36         cpu frequency.  Measuring the cycle counter against that would be
      37         possible though.  But currently we don't use the cycle counter due to
      38         unicos having int==8bytes where tune/alpha.asm assumes int==4bytes.
      39  
      40     m68040-unknown-netbsd1.4.1
      41         Not sure if the system even knows the cpu frequency.  There's no
      42         cycle counter to measure, though we could perhaps make a loop taking
      43         a known number of cycles and measure that.
      44  
      45     power-ibm-aix4.2.1.0
      46     power2-ibm-aix4.3.1.0
      47     powerpc604-ibm-aix4.3.1.0
      48     powerpc604-ibm-aix4.3.3.0
      49     powerpc630-ibm-aix4.3.3.0
      50     powerpc-unknown-netbsd1.6
      51         Don't know where any info hides on these.  mftb is not related to the
      52         cpu frequency so doesn't help.
      53  
      54     sparc-unknown-linux-gnu [maybe]
      55         Don't know where any info hides on this.
      56  
      57     t90-cray-unicos10.0.X
      58         The times() call seems to be for instance 2.22 nanoseconds, which
      59         might be the cpu frequency (450 mhz), but need to confirm that.
      60  
      61  */
      62  
      63  #include "config.h"
      64  
      65  #if HAVE_INVENT_H
      66  #include <invent.h> /* for IRIX invent_cpuinfo_t */
      67  #endif
      68  
      69  #include <stdio.h>
      70  #include <stdlib.h> /* for getenv, qsort */
      71  #include <string.h> /* for memcmp */
      72  
      73  #if HAVE_UNISTD_H
      74  #include <unistd.h> /* for sysconf */
      75  #endif
      76  
      77  #include <sys/types.h>
      78  
      79  #if HAVE_SYS_ATTRIBUTES_H
      80  #include <sys/attributes.h>   /* for IRIX attr_get(), needs sys/types.h */
      81  #endif
      82  
      83  #if HAVE_SYS_IOGRAPH_H
      84  #include <sys/iograph.h>      /* for IRIX INFO_LBL_DETAIL_INVENT */
      85  #endif
      86  
      87  #if HAVE_SYS_PARAM_H     /* for constants needed by NetBSD <sys/sysctl.h> */
      88  #include <sys/param.h>   /* and needed by HPUX <sys/pstat.h> */
      89  #endif
      90  
      91  #if HAVE_SYS_PSTAT_H
      92  #include <sys/pstat.h>   /* for HPUX pstat_getprocessor() */
      93  #endif
      94  
      95  #if HAVE_SYS_SYSCTL_H
      96  #include <sys/sysctl.h>  /* for sysctlbyname() */
      97  #endif
      98  
      99  #if TIME_WITH_SYS_TIME
     100  # include <sys/time.h>  /* for struct timeval */
     101  # include <time.h>
     102  #else
     103  # if HAVE_SYS_TIME_H
     104  #  include <sys/time.h>
     105  # else
     106  #  include <time.h>
     107  # endif
     108  #endif
     109  
     110  #if HAVE_SYS_RESOURCE_H
     111  #include <sys/resource.h>  /* for struct rusage */
     112  #endif
     113  
     114  #if HAVE_SYS_PROCESSOR_H
     115  #include <sys/processor.h>  /* for solaris processor_info_t */
     116  #endif
     117  
     118  /* On AIX 5.1 with gcc 2.9-aix51-020209 in -maix64 mode, <sys/sysinfo.h>
     119     gets an error about "fill" in "struct cpuinfo" having a negative size,
     120     apparently due to __64BIT_KERNEL not being defined because _KERNEL is not
     121     defined.  Avoid this file if we don't actually need it, which we don't on
     122     AIX since there's no getsysinfo there.  */
     123  #if HAVE_SYS_SYSINFO_H && HAVE_GETSYSINFO
     124  #include <sys/sysinfo.h>  /* for OSF getsysinfo */
     125  #endif
     126  
     127  #if HAVE_MACHINE_HAL_SYSINFO_H
     128  #include <machine/hal_sysinfo.h>  /* for OSF GSI_CPU_INFO, struct cpu_info */
     129  #endif
     130  
     131  /* Remove definitions from NetBSD <sys/param.h>, to avoid conflicts with
     132     gmp-impl.h. */
     133  #ifdef MIN
     134  #undef MIN
     135  #endif
     136  #ifdef MAX
     137  #undef MAX
     138  #endif
     139  
     140  #include "gmp-impl.h"
     141  
     142  #include "speed.h"
     143  
     144  
     145  #define HELP(str)                       \
     146    if (help)                             \
     147      {                                   \
     148        printf ("    - %s\n", str);       \
     149        return 0;                         \
     150      }
     151  
     152  
     153  /* GMP_CPU_FREQUENCY environment variable.  Should be in Hertz and can be
     154     floating point, for example "450e6". */
     155  static int
     156  freq_environment (int help)
     157  {
     158    char  *e;
     159  
     160    HELP ("environment variable GMP_CPU_FREQUENCY (in Hertz)");
     161  
     162    e = getenv ("GMP_CPU_FREQUENCY");
     163    if (e == NULL)
     164      return 0;
     165  
     166    speed_cycletime = 1.0 / atof (e);
     167  
     168    if (speed_option_verbose)
     169      printf ("Using GMP_CPU_FREQUENCY %.2f for cycle time %.3g\n",
     170              atof (e), speed_cycletime);
     171  
     172    return 1;
     173  }
     174  
     175  
     176  /* getsysinfo is available on OSF, or 4.0 and up at least.
     177     The man page (on 4.0) suggests a 0 return indicates information not
     178     available, but that seems to be the normal return for GSI_CPU_INFO.  */
     179  static int
     180  freq_getsysinfo (int help)
     181  {
     182  #if HAVE_GETSYSINFO
     183    struct cpu_info  c;
     184    int              start;
     185  
     186    HELP ("getsysinfo() GSI_CPU_INFO");
     187  
     188    start = 0;
     189    if (getsysinfo (GSI_CPU_INFO, (caddr_t) &c, sizeof (c),
     190                    &start, NULL, NULL) != -1)
     191      {
     192        speed_cycletime = 1e-6 / (double) c.mhz;
     193        if (speed_option_verbose)
     194          printf ("Using getsysinfo() GSI_CPU_INFO %u for cycle time %.3g\n",
     195                  c.mhz, speed_cycletime);
     196        return 1;
     197      }
     198  #endif
     199    return 0;
     200  }
     201  
     202  
     203  /* In HPUX 10 and up, pstat_getprocessor() psp_iticksperclktick is the
     204     number of CPU cycles (ie. the CR16 register) per CLK_TCK.  HPUX 9 doesn't
     205     have that field in pst_processor though, and has no apparent
     206     equivalent.  */
     207  
     208  static int
     209  freq_pstat_getprocessor (int help)
     210  {
     211  #if HAVE_PSTAT_GETPROCESSOR && HAVE_PSP_ITICKSPERCLKTICK
     212    struct pst_processor  p;
     213  
     214    HELP ("pstat_getprocessor() psp_iticksperclktick");
     215  
     216    if (pstat_getprocessor (&p, sizeof(p), 1, 0) != -1)
     217      {
     218        long  c = clk_tck();
     219        speed_cycletime = 1.0 / (c * p.psp_iticksperclktick);
     220        if (speed_option_verbose)
     221          printf ("Using pstat_getprocessor() psp_iticksperclktick %lu and clk_tck %ld for cycle time %.3g\n",
     222                  (unsigned long) p.psp_iticksperclktick, c,
     223                  speed_cycletime);
     224        return 1;
     225      }
     226  #endif
     227    return 0;
     228  }
     229  
     230  
     231  /* i386 FreeBSD 2.2.8 sysctlbyname machdep.i586_freq is in Hertz.
     232     There's no obvious defines available to get this from plain sysctl.  */
     233  static int
     234  freq_sysctlbyname_i586_freq (int help)
     235  {
     236  #if HAVE_SYSCTLBYNAME
     237    unsigned  val;
     238    size_t    size;
     239  
     240    HELP ("sysctlbyname() machdep.i586_freq");
     241  
     242    size = sizeof(val);
     243    if (sysctlbyname ("machdep.i586_freq", &val, &size, NULL, 0) == 0
     244        && size == sizeof(val))
     245      {
     246        speed_cycletime = 1.0 / (double) val;
     247        if (speed_option_verbose)
     248          printf ("Using sysctlbyname() machdep.i586_freq %u for cycle time %.3g\n",
     249                  val, speed_cycletime);
     250        return 1;
     251      }
     252  #endif
     253    return 0;
     254  }
     255  
     256  
     257  /* i368 FreeBSD 3.3 sysctlbyname machdep.tsc_freq is in Hertz.
     258     There's no obvious defines to get this from plain sysctl.  */
     259  
     260  static int
     261  freq_sysctlbyname_tsc_freq (int help)
     262  {
     263  #if HAVE_SYSCTLBYNAME
     264    unsigned  val;
     265    size_t    size;
     266  
     267    HELP ("sysctlbyname() machdep.tsc_freq");
     268  
     269    size = sizeof(val);
     270    if (sysctlbyname ("machdep.tsc_freq", &val, &size, NULL, 0) == 0
     271        && size == sizeof(val))
     272      {
     273        speed_cycletime = 1.0 / (double) val;
     274        if (speed_option_verbose)
     275          printf ("Using sysctlbyname() machdep.tsc_freq %u for cycle time %.3g\n",
     276                  val, speed_cycletime);
     277        return 1;
     278      }
     279  #endif
     280    return 0;
     281  }
     282  
     283  
     284  /* Apple powerpc Darwin 1.3 sysctl hw.cpufrequency is in hertz.  For some
     285     reason only seems to be available from sysctl(), not sysctlbyname().  */
     286  
     287  static int
     288  freq_sysctl_hw_cpufrequency (int help)
     289  {
     290  #if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_CPU_FREQ)
     291    int       mib[2];
     292    unsigned  val;
     293    size_t    size;
     294  
     295    HELP ("sysctl() hw.cpufrequency");
     296  
     297    mib[0] = CTL_HW;
     298    mib[1] = HW_CPU_FREQ;
     299    size = sizeof(val);
     300    if (sysctl (mib, 2, &val, &size, NULL, 0) == 0)
     301      {
     302        speed_cycletime = 1.0 / (double) val;
     303        if (speed_option_verbose)
     304          printf ("Using sysctl() hw.cpufrequency %u for cycle time %.3g\n",
     305                  val, speed_cycletime);
     306        return 1;
     307      }
     308  #endif
     309    return 0;
     310  }
     311  
     312  
     313  /* The following ssyctl hw.model strings have been observed,
     314  
     315         Alpha FreeBSD 4.1:   Digital AlphaPC 164LX 599 MHz
     316         NetBSD 1.4:          Digital AlphaPC 164LX 599 MHz
     317         NetBSD 1.6.1:        CY7C601 @ 40 MHz, TMS390C602A FPU
     318  
     319     NetBSD 1.4 doesn't seem to have sysctlbyname, so sysctl() is used.  */
     320  
     321  static int
     322  freq_sysctl_hw_model (int help)
     323  {
     324  #if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_MODEL)
     325    int       mib[2];
     326    char      str[128];
     327    unsigned  val;
     328    size_t    size;
     329    char      *p;
     330    int       end;
     331  
     332    HELP ("sysctl() hw.model");
     333  
     334    mib[0] = CTL_HW;
     335    mib[1] = HW_MODEL;
     336    size = sizeof(str);
     337    if (sysctl (mib, 2, str, &size, NULL, 0) == 0)
     338      {
     339        for (p = str; *p != '\0'; p++)
     340          {
     341            end = 0;
     342            if (sscanf (p, "%u MHz%n", &val, &end) == 1 && end != 0)
     343              {
     344                speed_cycletime = 1e-6 / (double) val;
     345                if (speed_option_verbose)
     346                  printf ("Using sysctl() hw.model %u for cycle time %.3g\n",
     347                          val, speed_cycletime);
     348                return 1;
     349              }
     350          }
     351      }
     352  #endif
     353    return 0;
     354  }
     355  
     356  
     357  /* /proc/cpuinfo for linux kernel.
     358  
     359     Linux doesn't seem to have any system call to get the CPU frequency, at
     360     least not in 2.0.x or 2.2.x, so it's necessary to read /proc/cpuinfo.
     361  
     362     i386 2.0.36 - "bogomips" is the CPU frequency.
     363  
     364     i386 2.2.13 - has both "cpu MHz" and "bogomips", and it's "cpu MHz" which
     365                   is the frequency.
     366  
     367     alpha 2.2.5 - "cycle frequency [Hz]" seems to be right, "BogoMIPS" is
     368                   very slightly different.
     369  
     370     alpha 2.2.18pre21 - "cycle frequency [Hz]" is 0 on at least one system,
     371                   "BogoMIPS" seems near enough.
     372  
     373     powerpc 2.2.19 - "clock" is the frequency, bogomips is something weird
     374    */
     375  
     376  static int
     377  freq_proc_cpuinfo (int help)
     378  {
     379    FILE    *fp;
     380    char    buf[128];
     381    double  val;
     382    int     ret = 0;
     383    int     end;
     384  
     385    HELP ("linux kernel /proc/cpuinfo file, cpu MHz or bogomips");
     386  
     387    if ((fp = fopen ("/proc/cpuinfo", "r")) != NULL)
     388      {
     389        while (fgets (buf, sizeof (buf), fp) != NULL)
     390          {
     391            if (sscanf (buf, "cycle frequency [Hz]    : %lf", &val) == 1
     392                && val != 0.0)
     393              {
     394                speed_cycletime = 1.0 / val;
     395                if (speed_option_verbose)
     396                  printf ("Using /proc/cpuinfo \"cycle frequency\" %.2f for cycle time %.3g\n", val, speed_cycletime);
     397                ret = 1;
     398                break;
     399              }
     400            if (sscanf (buf, "cpu MHz : %lf\n", &val) == 1)
     401              {
     402                speed_cycletime = 1e-6 / val;
     403                if (speed_option_verbose)
     404                  printf ("Using /proc/cpuinfo \"cpu MHz\" %.2f for cycle time %.3g\n", val, speed_cycletime);
     405                ret = 1;
     406                break;
     407              }
     408            end = 0;
     409            if (sscanf (buf, "clock : %lfMHz\n%n", &val, &end) == 1 && end != 0)
     410              {
     411                speed_cycletime = 1e-6 / val;
     412                if (speed_option_verbose)
     413                  printf ("Using /proc/cpuinfo \"clock\" %.2f for cycle time %.3g\n", val, speed_cycletime);
     414                ret = 1;
     415                break;
     416              }
     417            if (sscanf (buf, "bogomips : %lf\n", &val) == 1
     418                || sscanf (buf, "BogoMIPS : %lf\n", &val) == 1)
     419              {
     420                speed_cycletime = 1e-6 / val;
     421                if (speed_option_verbose)
     422                  printf ("Using /proc/cpuinfo \"bogomips\" %.2f for cycle time %.3g\n", val, speed_cycletime);
     423                ret = 1;
     424                break;
     425              }
     426          }
     427        fclose (fp);
     428      }
     429    return ret;
     430  }
     431  
     432  
     433  /* /bin/sysinfo for SunOS 4.
     434     Prints a line like: cpu0 is a "75 MHz TI,TMS390Z55" CPU */
     435  static int
     436  freq_sunos_sysinfo (int help)
     437  {
     438    int     ret = 0;
     439  #if HAVE_POPEN
     440    FILE    *fp;
     441    char    buf[128];
     442    double  val;
     443    int     end;
     444  
     445    HELP ("SunOS /bin/sysinfo program output, cpu0");
     446  
     447    /* Error messages are sent to /dev/null in case /bin/sysinfo doesn't
     448       exist.  The brackets are necessary for some shells. */
     449    if ((fp = popen ("(/bin/sysinfo) 2>/dev/null", "r")) != NULL)
     450      {
     451        while (fgets (buf, sizeof (buf), fp) != NULL)
     452          {
     453            end = 0;
     454            if (sscanf (buf, " cpu0 is a \"%lf MHz%n", &val, &end) == 1
     455                && end != 0)
     456              {
     457                speed_cycletime = 1e-6 / val;
     458                if (speed_option_verbose)
     459                  printf ("Using /bin/sysinfo \"cpu0 MHz\" %.2f for cycle time %.3g\n", val, speed_cycletime);
     460                ret = 1;
     461                break;
     462              }
     463          }
     464        pclose (fp);
     465      }
     466  #endif
     467    return ret;
     468  }
     469  
     470  
     471  /* "/etc/hw -r cpu" for SCO OpenUnix 8, printing a line like
     472  	The speed of the CPU is approximately 450MHz
     473   */
     474  static int
     475  freq_sco_etchw (int help)
     476  {
     477    int     ret = 0;
     478  #if HAVE_POPEN
     479    FILE    *fp;
     480    char    buf[128];
     481    double  val;
     482    int     end;
     483  
     484    HELP ("SCO /etc/hw program output");
     485  
     486    /* Error messages are sent to /dev/null in case /etc/hw doesn't exist.
     487       The brackets are necessary for some shells. */
     488    if ((fp = popen ("(/etc/hw -r cpu) 2>/dev/null", "r")) != NULL)
     489      {
     490        while (fgets (buf, sizeof (buf), fp) != NULL)
     491          {
     492            end = 0;
     493            if (sscanf (buf, " The speed of the CPU is approximately %lfMHz%n",
     494                        &val, &end) == 1 && end != 0)
     495              {
     496                speed_cycletime = 1e-6 / val;
     497                if (speed_option_verbose)
     498                  printf ("Using /etc/hw %.2f MHz, for cycle time %.3g\n",
     499                          val, speed_cycletime);
     500                ret = 1;
     501                break;
     502              }
     503          }
     504        pclose (fp);
     505      }
     506  #endif
     507    return ret;
     508  }
     509  
     510  
     511  /* attr_get("/hw/cpunum/0",INFO_LBL_DETAIL_INVENT) ic_cpu_info.cpufq for
     512     IRIX 6.5.  Past versions don't have INFO_LBL_DETAIL_INVENT,
     513     invent_cpuinfo_t, or /hw/cpunum/0.
     514  
     515     The same information is available from the "hinv -c processor" command,
     516     but it seems better to make a system call where possible. */
     517  
     518  static int
     519  freq_attr_get_invent (int help)
     520  {
     521    int     ret = 0;
     522  #if HAVE_ATTR_GET && HAVE_INVENT_H && defined (INFO_LBL_DETAIL_INVENT)
     523    invent_cpuinfo_t  inv;
     524    int               len, val;
     525  
     526    HELP ("attr_get(\"/hw/cpunum/0\") ic_cpu_info.cpufq");
     527  
     528    len = sizeof (inv);
     529    if (attr_get ("/hw/cpunum/0", INFO_LBL_DETAIL_INVENT,
     530                  (char *) &inv, &len, 0) == 0
     531        && len == sizeof (inv)
     532        && inv.ic_gen.ig_invclass == INV_PROCESSOR)
     533      {
     534        val = inv.ic_cpu_info.cpufq;
     535        speed_cycletime = 1e-6 / val;
     536        if (speed_option_verbose)
     537          printf ("Using attr_get(\"/hw/cpunum/0\") ic_cpu_info.cpufq %d MHz for cycle time %.3g\n", val, speed_cycletime);
     538        ret = 1;
     539      }
     540  #endif
     541    return ret;
     542  }
     543  
     544  
     545  /* FreeBSD on i386 gives a line like the following at bootup, and which can
     546     be read back from /var/run/dmesg.boot.
     547  
     548         CPU: AMD Athlon(tm) Processor (755.29-MHz 686-class CPU)
     549         CPU: Pentium 4 (1707.56-MHz 686-class CPU)
     550         CPU: i486 DX4 (486-class CPU)
     551  
     552     This is useful on FreeBSD 4.x, where there's no sysctl machdep.tsc_freq
     553     or machdep.i586_freq.
     554  
     555     It's better to use /var/run/dmesg.boot than to run /sbin/dmesg, since the
     556     latter prints the current system message buffer, which is a limited size
     557     and can wrap around if the system is up for a long time.  */
     558  
     559  static int
     560  freq_bsd_dmesg (int help)
     561  {
     562    FILE    *fp;
     563    char    buf[256], *p;
     564    double  val;
     565    int     ret = 0;
     566    int     end;
     567  
     568    HELP ("BSD /var/run/dmesg.boot file");
     569  
     570    if ((fp = fopen ("/var/run/dmesg.boot", "r")) != NULL)
     571      {
     572        while (fgets (buf, sizeof (buf), fp) != NULL)
     573          {
     574            if (memcmp (buf, "CPU:", 4) == 0)
     575              {
     576                for (p = buf; *p != '\0'; p++)
     577                  {
     578                    end = 0;
     579                    if (sscanf (p, "(%lf-MHz%n", &val, &end) == 1 && end != 0)
     580                      {
     581                        speed_cycletime = 1e-6 / val;
     582                        if (speed_option_verbose)
     583                          printf ("Using /var/run/dmesg.boot CPU: %.2f MHz for cycle time %.3g\n", val, speed_cycletime);
     584                        ret = 1;
     585                        break;
     586                      }
     587                  }
     588              }
     589          }
     590        fclose (fp);
     591      }
     592    return ret;
     593  }
     594  
     595  
     596  /* "hinv -c processor" for IRIX.  The following lines have been seen,
     597  
     598                1 150 MHZ IP20 Processor
     599                2 195 MHZ IP27 Processors
     600                Processor 0: 500 MHZ IP35
     601  
     602     This information is available from attr_get() on IRIX 6.5 (see above),
     603     but on IRIX 6.2 it's not clear where to look, so fall back on
     604     parsing.  */
     605  
     606  static int
     607  freq_irix_hinv (int help)
     608  {
     609    int     ret = 0;
     610  #if HAVE_POPEN
     611    FILE    *fp;
     612    char    buf[128];
     613    double  val;
     614    int     nproc, end;
     615  
     616    HELP ("IRIX \"hinv -c processor\" output");
     617  
     618    /* Error messages are sent to /dev/null in case hinv doesn't exist.  The
     619       brackets are necessary for some shells. */
     620    if ((fp = popen ("(hinv -c processor) 2>/dev/null", "r")) != NULL)
     621      {
     622        while (fgets (buf, sizeof (buf), fp) != NULL)
     623          {
     624            end = 0;
     625            if (sscanf (buf, "Processor 0: %lf MHZ%n", &val, &end) == 1
     626                && end != 0)
     627              {
     628              found:
     629                speed_cycletime = 1e-6 / val;
     630                if (speed_option_verbose)
     631                  printf ("Using hinv -c processor \"%.2f MHZ\" for cycle time %.3g\n", val, speed_cycletime);
     632                ret = 1;
     633                break;
     634              }
     635            end = 0;
     636            if (sscanf (buf, "%d %lf MHZ%n", &nproc, &val, &end) == 2
     637                && end != 0)
     638              goto found;
     639          }
     640        pclose (fp);
     641      }
     642  #endif
     643    return ret;
     644  }
     645  
     646  
     647  /* processor_info() for Solaris.  "psrinfo" is the command-line interface to
     648     this.  "prtconf -vp" gives similar information.
     649  
     650     Apple Darwin has a processor_info, but in an incompatible style.  It
     651     doesn't have <sys/processor.h>, so test for that.  */
     652  
     653  static int
     654  freq_processor_info (int help)
     655  {
     656  #if HAVE_PROCESSOR_INFO && HAVE_SYS_PROCESSOR_H
     657    processor_info_t  p;
     658    int  i, n, mhz = 0;
     659  
     660    HELP ("processor_info() pi_clock");
     661  
     662    n = sysconf (_SC_NPROCESSORS_CONF);
     663    for (i = 0; i < n; i++)
     664      {
     665        if (processor_info (i, &p) != 0)
     666          continue;
     667        if (p.pi_state != P_ONLINE)
     668          continue;
     669  
     670        if (mhz != 0 && p.pi_clock != mhz)
     671          {
     672            fprintf (stderr,
     673                     "freq_processor_info(): There's more than one CPU and they have different clock speeds\n");
     674            return 0;
     675          }
     676  
     677        mhz = p.pi_clock;
     678      }
     679  
     680    speed_cycletime = 1.0e-6 / (double) mhz;
     681  
     682    if (speed_option_verbose)
     683      printf ("Using processor_info() %d mhz for cycle time %.3g\n",
     684              mhz, speed_cycletime);
     685    return 1;
     686  
     687  #else
     688    return 0;
     689  #endif
     690  }
     691  
     692  
     693  #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY
     694  static double
     695  freq_measure_gettimeofday_one (void)
     696  {
     697  #define call_gettimeofday(t)   gettimeofday (&(t), NULL)
     698  #define timeval_tv_sec(t)      ((t).tv_sec)
     699  #define timeval_tv_usec(t)     ((t).tv_usec)
     700    FREQ_MEASURE_ONE ("gettimeofday", struct timeval,
     701                      call_gettimeofday, speed_cyclecounter,
     702                      timeval_tv_sec, timeval_tv_usec);
     703  }
     704  #endif
     705  
     706  #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE
     707  static double
     708  freq_measure_getrusage_one (void)
     709  {
     710  #define call_getrusage(t)   getrusage (0, &(t))
     711  #define rusage_tv_sec(t)    ((t).ru_utime.tv_sec)
     712  #define rusage_tv_usec(t)   ((t).ru_utime.tv_usec)
     713    FREQ_MEASURE_ONE ("getrusage", struct rusage,
     714                      call_getrusage, speed_cyclecounter,
     715                      rusage_tv_sec, rusage_tv_usec);
     716  }
     717  #endif
     718  
     719  
     720  /* MEASURE_MATCH is how many readings within MEASURE_TOLERANCE of each other
     721     are required.  This must be at least 2.  */
     722  #define MEASURE_MAX_ATTEMPTS   20
     723  #define MEASURE_TOLERANCE      1.005  /* 0.5% */
     724  #define MEASURE_MATCH          3
     725  
     726  double
     727  freq_measure (const char *name, double (*one) (void))
     728  {
     729    double  t[MEASURE_MAX_ATTEMPTS];
     730    int     i, j;
     731  
     732    for (i = 0; i < numberof (t); i++)
     733      {
     734        t[i] = (*one) ();
     735  
     736        qsort (t, i+1, sizeof(t[0]), (qsort_function_t) double_cmp_ptr);
     737        if (speed_option_verbose >= 3)
     738          for (j = 0; j <= i; j++)
     739            printf ("   t[%d] is %.6g\n", j, t[j]);
     740  
     741        for (j = 0; j+MEASURE_MATCH-1 <= i; j++)
     742          {
     743            if (t[j+MEASURE_MATCH-1] <= t[j] * MEASURE_TOLERANCE)
     744              {
     745                /* use the average of the range found */
     746                  return (t[j+MEASURE_MATCH-1] + t[j]) / 2.0;
     747              }
     748          }
     749      }
     750    return -1.0;
     751  }
     752  
     753  static int
     754  freq_measure_getrusage (int help)
     755  {
     756  #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE
     757    double  cycletime;
     758  
     759    if (! getrusage_microseconds_p ())
     760      return 0;
     761    if (! cycles_works_p ())
     762      return 0;
     763  
     764    HELP ("cycle counter measured with microsecond getrusage()");
     765  
     766    cycletime = freq_measure ("getrusage", freq_measure_getrusage_one);
     767    if (cycletime == -1.0)
     768      return 0;
     769  
     770    speed_cycletime = cycletime;
     771    if (speed_option_verbose)
     772      printf ("Using getrusage() measured cycle counter %.4g (%.2f MHz)\n",
     773              speed_cycletime, 1e-6/speed_cycletime);
     774    return 1;
     775  
     776  #else
     777    return 0;
     778  #endif
     779  }
     780  
     781  static int
     782  freq_measure_gettimeofday (int help)
     783  {
     784  #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY
     785    double  cycletime;
     786  
     787    if (! gettimeofday_microseconds_p ())
     788      return 0;
     789    if (! cycles_works_p ())
     790      return 0;
     791  
     792    HELP ("cycle counter measured with microsecond gettimeofday()");
     793  
     794    cycletime = freq_measure ("gettimeofday", freq_measure_gettimeofday_one);
     795    if (cycletime == -1.0)
     796      return 0;
     797  
     798    speed_cycletime = cycletime;
     799    if (speed_option_verbose)
     800      printf ("Using gettimeofday() measured cycle counter %.4g (%.2f MHz)\n",
     801              speed_cycletime, 1e-6/speed_cycletime);
     802    return 1;
     803  #else
     804    return 0;
     805  #endif
     806  }
     807  
     808  
     809  /* Each function returns 1 if it succeeds in setting speed_cycletime, or 0
     810     if not.
     811  
     812     In general system call tests are first since they're fast, then file
     813     tests, then tests running programs.  Necessary exceptions to this rule
     814     are noted.  The measuring is last since it's time consuming, and rather
     815     wasteful of cpu.  */
     816  
     817  static int
     818  freq_all (int help)
     819  {
     820    return
     821      /* This should be first, so an environment variable can override
     822         anything the system gives. */
     823      freq_environment (help)
     824  
     825      || freq_attr_get_invent (help)
     826      || freq_getsysinfo (help)
     827      || freq_pstat_getprocessor (help)
     828      || freq_sysctl_hw_model (help)
     829      || freq_sysctl_hw_cpufrequency (help)
     830      || freq_sysctlbyname_i586_freq (help)
     831      || freq_sysctlbyname_tsc_freq (help)
     832  
     833      /* SCO openunix 8 puts a dummy pi_clock==16 in processor_info, so be
     834         sure to check /etc/hw before that function. */
     835      || freq_sco_etchw (help)
     836  
     837      || freq_processor_info (help)
     838      || freq_proc_cpuinfo (help)
     839      || freq_bsd_dmesg (help)
     840      || freq_irix_hinv (help)
     841      || freq_sunos_sysinfo (help)
     842      || freq_measure_getrusage (help)
     843      || freq_measure_gettimeofday (help);
     844  }
     845  
     846  
     847  void
     848  speed_cycletime_init (void)
     849  {
     850    static int  attempted = 0;
     851  
     852    if (attempted)
     853      return;
     854    attempted = 1;
     855  
     856    if (freq_all (0))
     857      return;
     858  
     859    if (speed_option_verbose)
     860      printf ("CPU frequency couldn't be determined\n");
     861  }
     862  
     863  
     864  void
     865  speed_cycletime_fail (const char *str)
     866  {
     867    fprintf (stderr, "Measuring with: %s\n", speed_time_string);
     868    fprintf (stderr, "%s,\n", str);
     869    fprintf (stderr, "but none of the following are available,\n");
     870    freq_all (1);
     871    abort ();
     872  }
     873  
     874  /* speed_time_init leaves speed_cycletime set to either 0.0 or 1.0 when the
     875     CPU frequency is unknown.  0.0 is when the time base is in seconds, so
     876     that's no good if cycles are wanted.  1.0 is when the time base is in
     877     cycles, which conversely is no good if seconds are wanted.  */
     878  void
     879  speed_cycletime_need_cycles (void)
     880  {
     881    speed_time_init ();
     882    if (speed_cycletime == 0.0)
     883      speed_cycletime_fail
     884        ("Need to know CPU frequency to give times in cycles");
     885  }
     886  void
     887  speed_cycletime_need_seconds (void)
     888  {
     889    speed_time_init ();
     890    if (speed_cycletime == 1.0)
     891      speed_cycletime_fail
     892        ("Need to know CPU frequency to convert cycles to seconds");
     893  }