freq.c
上传用户:qaz666999
上传日期:2022-08-06
资源大小:2570k
文件大小:24k
源码类别:

数学计算

开发平台:

Unix_Linux

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