[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

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>