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

Annotation of OpenXM_contrib/gmp/tune/time.c, Revision 1.1

1.1     ! maekawa     1: /* Time routines for speed measurments. */
        !             2:
        !             3: /*
        !             4: Copyright (C) 1999, 2000 Free Software Foundation, Inc.
        !             5:
        !             6: This file is part of the GNU MP Library.
        !             7:
        !             8: The GNU MP Library is free software; you can redistribute it and/or modify
        !             9: it under the terms of the GNU Lesser General Public License as published by
        !            10: the Free Software Foundation; either version 2.1 of the License, or (at your
        !            11: option) any later version.
        !            12:
        !            13: The GNU MP Library is distributed in the hope that it will be useful, but
        !            14: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
        !            15: or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
        !            16: License for more details.
        !            17:
        !            18: You should have received a copy of the GNU Lesser General Public License
        !            19: along with the GNU MP Library; see the file COPYING.LIB.  If not, write to
        !            20: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
        !            21: MA 02111-1307, USA.
        !            22: */
        !            23:
        !            24: /* speed_time_init() - initialize timing things.  speed_starttime() calls
        !            25:    this if it hasn't been done yet, so you only need to call this explicitly
        !            26:    if you want to use the global variables before the first measurement.
        !            27:
        !            28:    speed_starttime() - start a time measurment.
        !            29:
        !            30:    speed_endtime() - end a time measurment, return time taken, in seconds.
        !            31:
        !            32:    speed_unittime - global variable with the unit of time measurement
        !            33:    accuracy, in seconds.
        !            34:
        !            35:    speed_precision - global variable which is the intended accuracy of time
        !            36:    measurements.  speed_measure() for instance runs target routines with
        !            37:    enough repetitions so it takes at least speed_unittime*speed_precision
        !            38:    seconds.  A program can provide an option so the user can set this.
        !            39:
        !            40:    speed_cycletime - the time in seconds for each CPU cycle, for example on
        !            41:    a 100 MHz CPU this would be 1.0e-8.  If the CPU frequency is unknown,
        !            42:    speed_cycletime is 1.0.  See speed_cycletime_init().
        !            43:
        !            44:    speed_time_string - a string describing the time method in use.
        !            45:
        !            46:
        !            47:    Enhancements:
        !            48:
        !            49:    Add support for accurate timing on more CPUs, machines and systems.
        !            50:
        !            51:    Extend automatic CPU frequency determination to more kernels and systems.
        !            52:
        !            53:  */
        !            54:
        !            55:
        !            56: #include <stdio.h>
        !            57: #include <stdlib.h> /* for getenv */
        !            58: #if HAVE_UNISTD_H
        !            59: #include <unistd.h>
        !            60: #endif
        !            61:
        !            62: #include <sys/types.h>
        !            63: #if HAVE_SYS_SYSCTL_H
        !            64: #include <sys/sysctl.h>
        !            65: #endif
        !            66:
        !            67: #include "gmp.h"
        !            68: #include "gmp-impl.h"
        !            69: #include "longlong.h"
        !            70:
        !            71: #include "speed.h"
        !            72:
        !            73:
        !            74: #if HAVE_SPEED_CYCLECOUNTER
        !            75: #define SPEED_USE_CYCLECOUNTER               1
        !            76: #else
        !            77: #define SPEED_USE_MICROSECOND_GETRUSAGE      0
        !            78: #define SPEED_USE_MICROSECOND_GETTIMEOFDAY   1
        !            79: #define SPEED_USE_TMS_UTIME                  0
        !            80: #endif
        !            81:
        !            82:
        !            83: #define TIMEVAL_SECS(tp) \
        !            84:   ((double) (tp)->tv_sec + (double) (tp)->tv_usec * 1.0e-6)
        !            85:
        !            86:
        !            87: /* Look for an environment variable for CPU clock frequency.
        !            88:    GMP_CPU_FREQUENCY should be in Hertz, in floating point form,
        !            89:    eg. "450e6". */
        !            90: int
        !            91: speed_cpu_frequency_environment (void)
        !            92: {
        !            93:   char  *e;
        !            94:
        !            95:   e = getenv ("GMP_CPU_FREQUENCY");
        !            96:   if (e == NULL)
        !            97:     return 0;
        !            98:
        !            99:   speed_cycletime = 1.0 / atof (e);
        !           100:   return 1;
        !           101: }
        !           102:
        !           103:
        !           104: /* On FreeBSD 3.3 the headers have #defines like CPU_WALLCLOCK under
        !           105:    CTL_MACHDEP but don't seem to have anything for machdep.tsc_freq or
        !           106:    machdep.i586_freq.  Using the string forms with sysctlbyname() works
        !           107:    though, and lets libc worry about the defines and headers.
        !           108:
        !           109:    FreeBSD 3.3 has tsc_freq, FreeBSD 2.2.8 has i586_freq instead.
        !           110:    The "sysctl -a" command prints everything available. */
        !           111:
        !           112: #if HAVE_SYSCTLBYNAME
        !           113: int
        !           114: speed_cpu_frequency_sysctlbyname (void)
        !           115: {
        !           116:   unsigned  val;
        !           117:   size_t    valsize;
        !           118:
        !           119:   valsize = sizeof(val);
        !           120:   if (sysctlbyname ("machdep.tsc_freq", &val, &valsize, NULL, 0) != 0
        !           121:       || valsize != sizeof(val))
        !           122:     {
        !           123:       valsize = sizeof(val);
        !           124:       if (sysctlbyname ("machdep.i586_freq", &val, &valsize, NULL, 0) != 0
        !           125:           || valsize != sizeof(val))
        !           126:         return 0;
        !           127:     }
        !           128:
        !           129:   speed_cycletime = 1.0 / (double) val;
        !           130:   return 1;
        !           131: }
        !           132: #endif
        !           133:
        !           134:
        !           135: /* Linux doesn't seem to have any system call to get the CPU frequency, at
        !           136:    least not in 2.0.x or 2.2.x, so it's necessary to read /proc/cpuinfo.
        !           137:
        !           138:    i386 2.0.36 - "bogomips" is the CPU frequency.
        !           139:
        !           140:    i386 2.2.13 - has both "cpu MHz" and "bogomips", and it's "cpu MHz" which
        !           141:                  is the frequency.
        !           142:
        !           143:    alpha 2.2.5 - "cycle frequency [Hz]" seems to be right, "BogoMIPS" is
        !           144:                  very slightly different.  */
        !           145:
        !           146: int
        !           147: speed_cpu_frequency_proc_cpuinfo (void)
        !           148: {
        !           149:   FILE    *fp;
        !           150:   char    buf[128];
        !           151:   double  val;
        !           152:   int     ret = 0;
        !           153:
        !           154:   if ((fp = fopen ("/proc/cpuinfo", "r")) != NULL)
        !           155:     {
        !           156:       while (fgets (buf, sizeof (buf), fp) != NULL)
        !           157:         {
        !           158:           if (sscanf (buf, "cycle frequency [Hz]    : %lf est.\n", &val) == 1)
        !           159:             {
        !           160:               speed_cycletime = 1.0 / val;
        !           161:               ret = 1;
        !           162:               break;
        !           163:             }
        !           164:           if (sscanf (buf, "cpu MHz  : %lf\n", &val) == 1)
        !           165:             {
        !           166:               speed_cycletime = 1e-6 / val;
        !           167:               ret = 1;
        !           168:               break;
        !           169:             }
        !           170:           if (sscanf (buf, "bogomips : %lf\n", &val) == 1)
        !           171:             {
        !           172:               speed_cycletime = 1e-6 / val;
        !           173:               ret = 1;
        !           174:               break;
        !           175:             }
        !           176:         }
        !           177:       fclose (fp);
        !           178:     }
        !           179:   return ret;
        !           180: }
        !           181:
        !           182:
        !           183: /* SunOS /bin/sysinfo prints a line like:
        !           184:        cpu0 is a "75 MHz TI,TMS390Z55" CPU */
        !           185:
        !           186: #if HAVE_POPEN
        !           187: int
        !           188: speed_cpu_frequency_sunos_sysinfo (void)
        !           189: {
        !           190:   FILE    *fp;
        !           191:   char    buf[128];
        !           192:   double  val;
        !           193:   int     ret = 0;
        !           194:
        !           195:   /* Error messages are sent to /dev/null in case /bin/sysinfo doesn't
        !           196:      exist.  The brackets are necessary for some shells (eg. ash). */
        !           197:   if ((fp = popen ("(/bin/sysinfo) 2>/dev/null", "r")) != NULL)
        !           198:     {
        !           199:       while (fgets (buf, sizeof (buf), fp) != NULL)
        !           200:         {
        !           201:           if (sscanf (buf, " cpu0 is a \"%lf MHz", &val) == 1)
        !           202:             {
        !           203:               speed_cycletime = 1e-6 / val;
        !           204:               ret = 1;
        !           205:               break;
        !           206:             }
        !           207:         }
        !           208:       pclose (fp);
        !           209:     }
        !           210:   return ret;
        !           211: }
        !           212: #endif
        !           213:
        !           214:
        !           215: /* This is for Solaris.  "psrinfo" is the command-line interface to
        !           216:    processor_info().  "prtconf -vp" gives similar information.  */
        !           217:
        !           218: #if HAVE_PROCESSOR_INFO
        !           219: #include <sys/unistd.h>     /* for _SC_NPROCESSORS_CONF */
        !           220: #include <sys/processor.h>  /* for processor_info_t */
        !           221: int
        !           222: speed_cpu_frequency_processor_info (void)
        !           223: {
        !           224:   processor_info_t  p;
        !           225:   int  i, n, mhz = 0;
        !           226:
        !           227:   n = sysconf (_SC_NPROCESSORS_CONF);
        !           228:   for (i = 0; i < n; i++)
        !           229:     {
        !           230:       if (processor_info (i, &p) != 0)
        !           231:         continue;
        !           232:       if (p.pi_state != P_ONLINE)
        !           233:         continue;
        !           234:
        !           235:       if (mhz != 0 && p.pi_clock != mhz)
        !           236:         {
        !           237:           fprintf (stderr,
        !           238:                    "speed_cpu_frequency_processor_info(): There's more than one CPU and they have different clock speeds\n");
        !           239:           return 0;
        !           240:         }
        !           241:
        !           242:       mhz = p.pi_clock;
        !           243:     }
        !           244:
        !           245:   speed_cycletime = 1.0e-6 / (double) mhz;
        !           246:   return 1;
        !           247: }
        !           248: #endif
        !           249:
        !           250:
        !           251: /* Each function returns 1 if it succeeds in setting speed_cycletime, or 0
        !           252:    if not.  */
        !           253:
        !           254: static const struct {
        !           255:   int         (*fun) _PROTO ((void));
        !           256:   const char  *description;
        !           257:
        !           258: } speed_cpu_frequency_table[] = {
        !           259:
        !           260:   /* This should be first, so an environment variable can override anything
        !           261:      the system gives. */
        !           262:   { speed_cpu_frequency_environment,
        !           263:     "environment variable GMP_CPU_FREQUENCY (in Hertz)" },
        !           264:
        !           265: #if HAVE_SYSCTLBYNAME
        !           266:   { speed_cpu_frequency_sysctlbyname,
        !           267:     "sysctlbyname() machdep.tsc_freq or machdep.i586_freq" },
        !           268: #endif
        !           269:
        !           270: #if HAVE_PROCESSOR_INFO
        !           271:   { speed_cpu_frequency_processor_info,
        !           272:     "processor_info() pi_clock" },
        !           273: #endif
        !           274:
        !           275:   { speed_cpu_frequency_proc_cpuinfo,
        !           276:     "linux kernel /proc/cpuinfo file, cpu MHz or bogomips" },
        !           277:
        !           278: #if HAVE_POPEN
        !           279:   { speed_cpu_frequency_sunos_sysinfo,
        !           280:     "SunOS /bin/sysinfo program cpu0 output" },
        !           281: #endif
        !           282: };
        !           283:
        !           284:
        !           285: int
        !           286: speed_cycletime_init (void)
        !           287: {
        !           288:   int  i;
        !           289:
        !           290:   for (i = 0; i < numberof (speed_cpu_frequency_table); i++)
        !           291:     if ((*speed_cpu_frequency_table[i].fun)())
        !           292:       return 1;
        !           293:
        !           294:   fprintf (stderr,
        !           295:            "Cannot determine CPU frequency, need one of the following\n");
        !           296:   for (i = 0; i < numberof (speed_cpu_frequency_table); i++)
        !           297:     fprintf (stderr, "\t- %s\n", speed_cpu_frequency_table[i].description);
        !           298:
        !           299:   return 0;
        !           300: }
        !           301:
        !           302:
        !           303: /* ---------------------------------------------------------------------- */
        !           304: #if SPEED_USE_CYCLECOUNTER
        !           305:
        !           306: const char *speed_time_string
        !           307:   = "Time measurements using CPU cycle counter.\n";
        !           308:
        !           309: /* bigish value because we have a fast timer */
        !           310: int speed_precision = 10000;
        !           311:
        !           312: double speed_unittime;
        !           313: double speed_cycletime;
        !           314:
        !           315: static int  speed_time_initialized = 0;
        !           316: static unsigned  speed_starttime_save[2];
        !           317:
        !           318: /* Knowing the CPU frequency is mandatory, so cycles can be converted to
        !           319:    seconds.  */
        !           320: void
        !           321: speed_time_init (void)
        !           322: {
        !           323:   if (speed_time_initialized)
        !           324:     return;
        !           325:   speed_time_initialized = 1;
        !           326:
        !           327:   if (!speed_cycletime_init ())
        !           328:     exit (1);
        !           329:
        !           330:   speed_unittime = speed_cycletime;
        !           331: }
        !           332:
        !           333: void
        !           334: speed_starttime (void)
        !           335: {
        !           336:   if (!speed_time_initialized)
        !           337:     speed_time_init ();
        !           338:   speed_cyclecounter (speed_starttime_save);
        !           339: }
        !           340:
        !           341: #define M_2POWU   ((double) (1L << (BITS_PER_INT-2)) * 4.0)
        !           342: #define M_2POW32  4294967296.0
        !           343:
        !           344: double
        !           345: speed_endtime (void)
        !           346: {
        !           347:   unsigned  endtime[2], e0;
        !           348:   double    t;
        !           349:
        !           350:   speed_cyclecounter (endtime);
        !           351:
        !           352:   /* This still works even if speed_cyclecounter() puts a value bigger than
        !           353:      32-bits in the low word.  The start and end values are allowed to
        !           354:      cancel in uints in case a uint is more than the 53 bits that will
        !           355:      normally fit in a double. */
        !           356:   e0 = endtime[0] - speed_starttime_save[0];
        !           357:   t = e0 - (e0 > endtime[0] ? M_2POWU : 0);
        !           358:   t += (endtime[1] - speed_starttime_save[1]) * M_2POW32;
        !           359:
        !           360:   return t * speed_unittime;
        !           361: }
        !           362:
        !           363: #endif
        !           364:
        !           365:
        !           366: /* ---------------------------------------------------------------------- */
        !           367: #if SPEED_USE_MICROSECOND_GETRUSAGE
        !           368: #include <sys/types.h>
        !           369: #include <sys/time.h>
        !           370: #include <sys/resource.h>
        !           371:
        !           372: const char *speed_time_string
        !           373:   = "Time measurements using microsecond accurate getrusage.\n";
        !           374:
        !           375: int speed_precision = 1000;
        !           376:
        !           377: double speed_unittime = 1.0e-6;
        !           378: double speed_cycletime = 1.0;
        !           379:
        !           380: static struct rusage  speed_starttime_save;
        !           381: static int  speed_time_initialized = 0;
        !           382:
        !           383: void
        !           384: speed_time_init (void)
        !           385: {
        !           386:   if (speed_time_initialized)
        !           387:     return;
        !           388:   speed_time_initialized = 1;
        !           389:
        !           390:   speed_cycletime_init ();
        !           391: }
        !           392:
        !           393: void
        !           394: speed_starttime (void)
        !           395: {
        !           396:   if (!speed_time_initialized)
        !           397:     speed_time_init ();
        !           398:
        !           399:   getrusage (0, &speed_starttime_save);
        !           400: }
        !           401:
        !           402: double
        !           403: speed_endtime (void)
        !           404: {
        !           405:   struct rusage r;
        !           406:
        !           407:   getrusage (0, &r);
        !           408:   return TIMEVAL_SECS (&r.ru_utime)
        !           409:     - TIMEVAL_SECS (&speed_starttime_save.ru_utime);
        !           410: }
        !           411: #endif
        !           412:
        !           413:
        !           414: /* ---------------------------------------------------------------------- */
        !           415: #if SPEED_USE_MICROSECOND_GETTIMEOFDAY
        !           416: /* This method is for systems with a microsecond accurate gettimeofday().
        !           417:
        !           418:    A dummy timezone parameter is always given to gettimeofday(), in case it
        !           419:    doesn't allow NULL.  */
        !           420:
        !           421: #include <sys/time.h>
        !           422:
        !           423: const char *speed_time_string
        !           424:   = "Time measurements using microsecond accurate gettimeofday.\n";
        !           425:
        !           426: /* highish value because we have an accurate timer */
        !           427: int speed_precision = 1000;
        !           428:
        !           429: double speed_unittime = 1.0e-6;
        !           430: double speed_cycletime = 1.0;
        !           431:
        !           432: static struct timeval  speed_starttime_save;
        !           433: static int  speed_time_initialized = 0;
        !           434:
        !           435: void
        !           436: speed_time_init (void)
        !           437: {
        !           438:   if (speed_time_initialized)
        !           439:     return;
        !           440:   speed_time_initialized = 1;
        !           441:
        !           442:   speed_cycletime_init ();
        !           443: }
        !           444:
        !           445: void
        !           446: speed_starttime (void)
        !           447: {
        !           448:   struct timezone  tz;
        !           449:   if (!speed_time_initialized)
        !           450:     speed_time_init ();
        !           451:
        !           452:   gettimeofday (&speed_starttime_save, &tz);
        !           453: }
        !           454:
        !           455: double
        !           456: speed_endtime (void)
        !           457: {
        !           458:   struct timeval   t;
        !           459:   struct timezone  tz;
        !           460:
        !           461:   gettimeofday (&t, &tz);
        !           462:   return TIMEVAL_SECS (&t) - TIMEVAL_SECS (&speed_starttime_save);
        !           463: }
        !           464:
        !           465: #endif
        !           466:
        !           467:
        !           468: /* ---------------------------------------------------------------------- */
        !           469: #if SPEED_USE_TMS_UTIME
        !           470: /* You're in trouble if you have to use this method.  Speed measurments and
        !           471:    threshold tuning are going to take a long time. */
        !           472:
        !           473: #if STDC_HEADERS
        !           474: #include <errno.h>      /* for errno */
        !           475: #include <string.h>     /* for strerror */
        !           476: #endif
        !           477: #if HAVE_UNISTD_H
        !           478: #include <unistd.h>     /* for sysconf */
        !           479: #endif
        !           480: #include <sys/times.h>  /* for times */
        !           481:
        !           482: const char *speed_time_string
        !           483:   = "Time measurements using tms_utime.\n";
        !           484:
        !           485:
        !           486: /* lowish default value so we don't take days and days to do tuning */
        !           487: int  speed_precision = 200;
        !           488:
        !           489: double  speed_unittime;
        !           490: double  speed_cycletime = 1.0;
        !           491:
        !           492: static struct tms  speed_starttime_save;
        !           493: static int  speed_time_initialized = 0;
        !           494:
        !           495: void
        !           496: speed_time_init (void)
        !           497: {
        !           498:   long  clk_tck;
        !           499:
        !           500:   if (speed_time_initialized)
        !           501:     return;
        !           502:   speed_time_initialized = 1;
        !           503:
        !           504:   speed_cycletime_init ();
        !           505:
        !           506: #if HAVE_SYSCONF
        !           507:   clk_tck = sysconf (_SC_CLK_TCK);
        !           508:   if (clk_tck == -1L)
        !           509:     {
        !           510:       fprintf (stderr, "sysconf(_SC_CLK_TCK) not available: %s\n",
        !           511:               strerror(errno));
        !           512:       fprintf (stderr, "\tusing CLK_TCK instead\n");
        !           513:       clk_tck = CLK_TCK;
        !           514:     }
        !           515: #else
        !           516:   clk_tck = CLK_TCK;
        !           517: #endif
        !           518:
        !           519:   speed_unittime = 1.0 / (double) clk_tck;
        !           520: }
        !           521:
        !           522: /* Burn up CPU until a times() tms_utime tick boundary.
        !           523:    Doing so lets you know a measurement has started on a tick boundary,
        !           524:    effectively halving the uncertainty in the measurement.
        !           525:    *t1 gets the start times() values the caller should use. */
        !           526: void
        !           527: times_utime_boundary (struct tms *t1)
        !           528: {
        !           529:   struct tms  t2;
        !           530:   times (&t2);
        !           531:   do
        !           532:     times (t1);
        !           533:   while (t1->tms_utime == t2.tms_utime);
        !           534: }
        !           535:
        !           536: void
        !           537: speed_starttime (void)
        !           538: {
        !           539:   if (!speed_time_initialized)
        !           540:     speed_time_init ();
        !           541:   times_utime_boundary (&speed_starttime_save);
        !           542: }
        !           543:
        !           544: double
        !           545: speed_endtime (void)
        !           546: {
        !           547:   struct tms  t;
        !           548:   times (&t);
        !           549:   return (t.tms_utime - speed_starttime_save.tms_utime) * speed_unittime;
        !           550: }
        !           551:
        !           552: #endif

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