[BACK]Return to freq.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib / gmp / tune

Annotation of OpenXM_contrib/gmp/tune/freq.c, Revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>