[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     ! 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>