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