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>