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