github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/tune/freq.c (about)

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