1 /* CPU frequency determination. 2 3 Copyright 1999-2004 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 either: 9 10 * the GNU Lesser General Public License as published by the Free 11 Software Foundation; either version 3 of the License, or (at your 12 option) any later version. 13 14 or 15 16 * the GNU General Public License as published by the Free Software 17 Foundation; either version 2 of the License, or (at your option) any 18 later version. 19 20 or both in parallel, as here. 21 22 The GNU MP Library is distributed in the hope that it will be useful, but 23 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 24 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 25 for more details. 26 27 You should have received copies of the GNU General Public License and the 28 GNU Lesser General Public License along with the GNU MP Library. If not, 29 see https://www.gnu.org/licenses/. */ 30 31 32 /* Currently we don't get a CPU frequency on the following systems, 33 34 alphaev5-cray-unicosmk2.0.6.X 35 times() has been seen at 13.33 ns (75 MHz), which is probably not the 36 cpu frequency. Measuring the cycle counter against that would be 37 possible though. But currently we don't use the cycle counter due to 38 unicos having int==8bytes where tune/alpha.asm assumes int==4bytes. 39 40 m68040-unknown-netbsd1.4.1 41 Not sure if the system even knows the cpu frequency. There's no 42 cycle counter to measure, though we could perhaps make a loop taking 43 a known number of cycles and measure that. 44 45 power-ibm-aix4.2.1.0 46 power2-ibm-aix4.3.1.0 47 powerpc604-ibm-aix4.3.1.0 48 powerpc604-ibm-aix4.3.3.0 49 powerpc630-ibm-aix4.3.3.0 50 powerpc-unknown-netbsd1.6 51 Don't know where any info hides on these. mftb is not related to the 52 cpu frequency so doesn't help. 53 54 sparc-unknown-linux-gnu [maybe] 55 Don't know where any info hides on this. 56 57 t90-cray-unicos10.0.X 58 The times() call seems to be for instance 2.22 nanoseconds, which 59 might be the cpu frequency (450 mhz), but need to confirm that. 60 61 */ 62 63 #include "config.h" 64 65 #if HAVE_INVENT_H 66 #include <invent.h> /* for IRIX invent_cpuinfo_t */ 67 #endif 68 69 #include <stdio.h> 70 #include <stdlib.h> /* for getenv, qsort */ 71 #include <string.h> /* for memcmp */ 72 73 #if HAVE_UNISTD_H 74 #include <unistd.h> /* for sysconf */ 75 #endif 76 77 #include <sys/types.h> 78 79 #if HAVE_SYS_ATTRIBUTES_H 80 #include <sys/attributes.h> /* for IRIX attr_get(), needs sys/types.h */ 81 #endif 82 83 #if HAVE_SYS_IOGRAPH_H 84 #include <sys/iograph.h> /* for IRIX INFO_LBL_DETAIL_INVENT */ 85 #endif 86 87 #if HAVE_SYS_PARAM_H /* for constants needed by NetBSD <sys/sysctl.h> */ 88 #include <sys/param.h> /* and needed by HPUX <sys/pstat.h> */ 89 #endif 90 91 #if HAVE_SYS_PSTAT_H 92 #include <sys/pstat.h> /* for HPUX pstat_getprocessor() */ 93 #endif 94 95 #if HAVE_SYS_SYSCTL_H 96 #include <sys/sysctl.h> /* for sysctlbyname() */ 97 #endif 98 99 #if TIME_WITH_SYS_TIME 100 # include <sys/time.h> /* for struct timeval */ 101 # include <time.h> 102 #else 103 # if HAVE_SYS_TIME_H 104 # include <sys/time.h> 105 # else 106 # include <time.h> 107 # endif 108 #endif 109 110 #if HAVE_SYS_RESOURCE_H 111 #include <sys/resource.h> /* for struct rusage */ 112 #endif 113 114 #if HAVE_SYS_PROCESSOR_H 115 #include <sys/processor.h> /* for solaris processor_info_t */ 116 #endif 117 118 /* On AIX 5.1 with gcc 2.9-aix51-020209 in -maix64 mode, <sys/sysinfo.h> 119 gets an error about "fill" in "struct cpuinfo" having a negative size, 120 apparently due to __64BIT_KERNEL not being defined because _KERNEL is not 121 defined. Avoid this file if we don't actually need it, which we don't on 122 AIX since there's no getsysinfo there. */ 123 #if HAVE_SYS_SYSINFO_H && HAVE_GETSYSINFO 124 #include <sys/sysinfo.h> /* for OSF getsysinfo */ 125 #endif 126 127 #if HAVE_MACHINE_HAL_SYSINFO_H 128 #include <machine/hal_sysinfo.h> /* for OSF GSI_CPU_INFO, struct cpu_info */ 129 #endif 130 131 /* Remove definitions from NetBSD <sys/param.h>, to avoid conflicts with 132 gmp-impl.h. */ 133 #ifdef MIN 134 #undef MIN 135 #endif 136 #ifdef MAX 137 #undef MAX 138 #endif 139 140 #include "gmp-impl.h" 141 142 #include "speed.h" 143 144 145 #define HELP(str) \ 146 if (help) \ 147 { \ 148 printf (" - %s\n", str); \ 149 return 0; \ 150 } 151 152 153 /* GMP_CPU_FREQUENCY environment variable. Should be in Hertz and can be 154 floating point, for example "450e6". */ 155 static int 156 freq_environment (int help) 157 { 158 char *e; 159 160 HELP ("environment variable GMP_CPU_FREQUENCY (in Hertz)"); 161 162 e = getenv ("GMP_CPU_FREQUENCY"); 163 if (e == NULL) 164 return 0; 165 166 speed_cycletime = 1.0 / atof (e); 167 168 if (speed_option_verbose) 169 printf ("Using GMP_CPU_FREQUENCY %.2f for cycle time %.3g\n", 170 atof (e), speed_cycletime); 171 172 return 1; 173 } 174 175 176 /* getsysinfo is available on OSF, or 4.0 and up at least. 177 The man page (on 4.0) suggests a 0 return indicates information not 178 available, but that seems to be the normal return for GSI_CPU_INFO. */ 179 static int 180 freq_getsysinfo (int help) 181 { 182 #if HAVE_GETSYSINFO 183 struct cpu_info c; 184 int start; 185 186 HELP ("getsysinfo() GSI_CPU_INFO"); 187 188 start = 0; 189 if (getsysinfo (GSI_CPU_INFO, (caddr_t) &c, sizeof (c), 190 &start, NULL, NULL) != -1) 191 { 192 speed_cycletime = 1e-6 / (double) c.mhz; 193 if (speed_option_verbose) 194 printf ("Using getsysinfo() GSI_CPU_INFO %u for cycle time %.3g\n", 195 c.mhz, speed_cycletime); 196 return 1; 197 } 198 #endif 199 return 0; 200 } 201 202 203 /* In HPUX 10 and up, pstat_getprocessor() psp_iticksperclktick is the 204 number of CPU cycles (ie. the CR16 register) per CLK_TCK. HPUX 9 doesn't 205 have that field in pst_processor though, and has no apparent 206 equivalent. */ 207 208 static int 209 freq_pstat_getprocessor (int help) 210 { 211 #if HAVE_PSTAT_GETPROCESSOR && HAVE_PSP_ITICKSPERCLKTICK 212 struct pst_processor p; 213 214 HELP ("pstat_getprocessor() psp_iticksperclktick"); 215 216 if (pstat_getprocessor (&p, sizeof(p), 1, 0) != -1) 217 { 218 long c = clk_tck(); 219 speed_cycletime = 1.0 / (c * p.psp_iticksperclktick); 220 if (speed_option_verbose) 221 printf ("Using pstat_getprocessor() psp_iticksperclktick %lu and clk_tck %ld for cycle time %.3g\n", 222 (unsigned long) p.psp_iticksperclktick, c, 223 speed_cycletime); 224 return 1; 225 } 226 #endif 227 return 0; 228 } 229 230 231 /* i386 FreeBSD 2.2.8 sysctlbyname machdep.i586_freq is in Hertz. 232 There's no obvious defines available to get this from plain sysctl. */ 233 static int 234 freq_sysctlbyname_i586_freq (int help) 235 { 236 #if HAVE_SYSCTLBYNAME 237 unsigned val; 238 size_t size; 239 240 HELP ("sysctlbyname() machdep.i586_freq"); 241 242 size = sizeof(val); 243 if (sysctlbyname ("machdep.i586_freq", &val, &size, NULL, 0) == 0 244 && size == sizeof(val)) 245 { 246 speed_cycletime = 1.0 / (double) val; 247 if (speed_option_verbose) 248 printf ("Using sysctlbyname() machdep.i586_freq %u for cycle time %.3g\n", 249 val, speed_cycletime); 250 return 1; 251 } 252 #endif 253 return 0; 254 } 255 256 257 /* i368 FreeBSD 3.3 sysctlbyname machdep.tsc_freq is in Hertz. 258 There's no obvious defines to get this from plain sysctl. */ 259 260 static int 261 freq_sysctlbyname_tsc_freq (int help) 262 { 263 #if HAVE_SYSCTLBYNAME 264 unsigned val; 265 size_t size; 266 267 HELP ("sysctlbyname() machdep.tsc_freq"); 268 269 size = sizeof(val); 270 if (sysctlbyname ("machdep.tsc_freq", &val, &size, NULL, 0) == 0 271 && size == sizeof(val)) 272 { 273 speed_cycletime = 1.0 / (double) val; 274 if (speed_option_verbose) 275 printf ("Using sysctlbyname() machdep.tsc_freq %u for cycle time %.3g\n", 276 val, speed_cycletime); 277 return 1; 278 } 279 #endif 280 return 0; 281 } 282 283 284 /* Apple powerpc Darwin 1.3 sysctl hw.cpufrequency is in hertz. For some 285 reason only seems to be available from sysctl(), not sysctlbyname(). */ 286 287 static int 288 freq_sysctl_hw_cpufrequency (int help) 289 { 290 #if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_CPU_FREQ) 291 int mib[2]; 292 unsigned val; 293 size_t size; 294 295 HELP ("sysctl() hw.cpufrequency"); 296 297 mib[0] = CTL_HW; 298 mib[1] = HW_CPU_FREQ; 299 size = sizeof(val); 300 if (sysctl (mib, 2, &val, &size, NULL, 0) == 0) 301 { 302 speed_cycletime = 1.0 / (double) val; 303 if (speed_option_verbose) 304 printf ("Using sysctl() hw.cpufrequency %u for cycle time %.3g\n", 305 val, speed_cycletime); 306 return 1; 307 } 308 #endif 309 return 0; 310 } 311 312 313 /* The following ssyctl hw.model strings have been observed, 314 315 Alpha FreeBSD 4.1: Digital AlphaPC 164LX 599 MHz 316 NetBSD 1.4: Digital AlphaPC 164LX 599 MHz 317 NetBSD 1.6.1: CY7C601 @ 40 MHz, TMS390C602A FPU 318 319 NetBSD 1.4 doesn't seem to have sysctlbyname, so sysctl() is used. */ 320 321 static int 322 freq_sysctl_hw_model (int help) 323 { 324 #if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_MODEL) 325 int mib[2]; 326 char str[128]; 327 unsigned val; 328 size_t size; 329 char *p; 330 int end; 331 332 HELP ("sysctl() hw.model"); 333 334 mib[0] = CTL_HW; 335 mib[1] = HW_MODEL; 336 size = sizeof(str); 337 if (sysctl (mib, 2, str, &size, NULL, 0) == 0) 338 { 339 for (p = str; *p != '\0'; p++) 340 { 341 end = 0; 342 if (sscanf (p, "%u MHz%n", &val, &end) == 1 && end != 0) 343 { 344 speed_cycletime = 1e-6 / (double) val; 345 if (speed_option_verbose) 346 printf ("Using sysctl() hw.model %u for cycle time %.3g\n", 347 val, speed_cycletime); 348 return 1; 349 } 350 } 351 } 352 #endif 353 return 0; 354 } 355 356 357 /* /proc/cpuinfo for linux kernel. 358 359 Linux doesn't seem to have any system call to get the CPU frequency, at 360 least not in 2.0.x or 2.2.x, so it's necessary to read /proc/cpuinfo. 361 362 i386 2.0.36 - "bogomips" is the CPU frequency. 363 364 i386 2.2.13 - has both "cpu MHz" and "bogomips", and it's "cpu MHz" which 365 is the frequency. 366 367 alpha 2.2.5 - "cycle frequency [Hz]" seems to be right, "BogoMIPS" is 368 very slightly different. 369 370 alpha 2.2.18pre21 - "cycle frequency [Hz]" is 0 on at least one system, 371 "BogoMIPS" seems near enough. 372 373 powerpc 2.2.19 - "clock" is the frequency, bogomips is something weird 374 */ 375 376 static int 377 freq_proc_cpuinfo (int help) 378 { 379 FILE *fp; 380 char buf[128]; 381 double val; 382 int ret = 0; 383 int end; 384 385 HELP ("linux kernel /proc/cpuinfo file, cpu MHz or bogomips"); 386 387 if ((fp = fopen ("/proc/cpuinfo", "r")) != NULL) 388 { 389 while (fgets (buf, sizeof (buf), fp) != NULL) 390 { 391 if (sscanf (buf, "cycle frequency [Hz] : %lf", &val) == 1 392 && val != 0.0) 393 { 394 speed_cycletime = 1.0 / val; 395 if (speed_option_verbose) 396 printf ("Using /proc/cpuinfo \"cycle frequency\" %.2f for cycle time %.3g\n", val, speed_cycletime); 397 ret = 1; 398 break; 399 } 400 if (sscanf (buf, "cpu MHz : %lf\n", &val) == 1) 401 { 402 speed_cycletime = 1e-6 / val; 403 if (speed_option_verbose) 404 printf ("Using /proc/cpuinfo \"cpu MHz\" %.2f for cycle time %.3g\n", val, speed_cycletime); 405 ret = 1; 406 break; 407 } 408 end = 0; 409 if (sscanf (buf, "clock : %lfMHz\n%n", &val, &end) == 1 && end != 0) 410 { 411 speed_cycletime = 1e-6 / val; 412 if (speed_option_verbose) 413 printf ("Using /proc/cpuinfo \"clock\" %.2f for cycle time %.3g\n", val, speed_cycletime); 414 ret = 1; 415 break; 416 } 417 if (sscanf (buf, "bogomips : %lf\n", &val) == 1 418 || sscanf (buf, "BogoMIPS : %lf\n", &val) == 1) 419 { 420 speed_cycletime = 1e-6 / val; 421 if (speed_option_verbose) 422 printf ("Using /proc/cpuinfo \"bogomips\" %.2f for cycle time %.3g\n", val, speed_cycletime); 423 ret = 1; 424 break; 425 } 426 } 427 fclose (fp); 428 } 429 return ret; 430 } 431 432 433 /* /bin/sysinfo for SunOS 4. 434 Prints a line like: cpu0 is a "75 MHz TI,TMS390Z55" CPU */ 435 static int 436 freq_sunos_sysinfo (int help) 437 { 438 int ret = 0; 439 #if HAVE_POPEN 440 FILE *fp; 441 char buf[128]; 442 double val; 443 int end; 444 445 HELP ("SunOS /bin/sysinfo program output, cpu0"); 446 447 /* Error messages are sent to /dev/null in case /bin/sysinfo doesn't 448 exist. The brackets are necessary for some shells. */ 449 if ((fp = popen ("(/bin/sysinfo) 2>/dev/null", "r")) != NULL) 450 { 451 while (fgets (buf, sizeof (buf), fp) != NULL) 452 { 453 end = 0; 454 if (sscanf (buf, " cpu0 is a \"%lf MHz%n", &val, &end) == 1 455 && end != 0) 456 { 457 speed_cycletime = 1e-6 / val; 458 if (speed_option_verbose) 459 printf ("Using /bin/sysinfo \"cpu0 MHz\" %.2f for cycle time %.3g\n", val, speed_cycletime); 460 ret = 1; 461 break; 462 } 463 } 464 pclose (fp); 465 } 466 #endif 467 return ret; 468 } 469 470 471 /* "/etc/hw -r cpu" for SCO OpenUnix 8, printing a line like 472 The speed of the CPU is approximately 450MHz 473 */ 474 static int 475 freq_sco_etchw (int help) 476 { 477 int ret = 0; 478 #if HAVE_POPEN 479 FILE *fp; 480 char buf[128]; 481 double val; 482 int end; 483 484 HELP ("SCO /etc/hw program output"); 485 486 /* Error messages are sent to /dev/null in case /etc/hw doesn't exist. 487 The brackets are necessary for some shells. */ 488 if ((fp = popen ("(/etc/hw -r cpu) 2>/dev/null", "r")) != NULL) 489 { 490 while (fgets (buf, sizeof (buf), fp) != NULL) 491 { 492 end = 0; 493 if (sscanf (buf, " The speed of the CPU is approximately %lfMHz%n", 494 &val, &end) == 1 && end != 0) 495 { 496 speed_cycletime = 1e-6 / val; 497 if (speed_option_verbose) 498 printf ("Using /etc/hw %.2f MHz, for cycle time %.3g\n", 499 val, speed_cycletime); 500 ret = 1; 501 break; 502 } 503 } 504 pclose (fp); 505 } 506 #endif 507 return ret; 508 } 509 510 511 /* attr_get("/hw/cpunum/0",INFO_LBL_DETAIL_INVENT) ic_cpu_info.cpufq for 512 IRIX 6.5. Past versions don't have INFO_LBL_DETAIL_INVENT, 513 invent_cpuinfo_t, or /hw/cpunum/0. 514 515 The same information is available from the "hinv -c processor" command, 516 but it seems better to make a system call where possible. */ 517 518 static int 519 freq_attr_get_invent (int help) 520 { 521 int ret = 0; 522 #if HAVE_ATTR_GET && HAVE_INVENT_H && defined (INFO_LBL_DETAIL_INVENT) 523 invent_cpuinfo_t inv; 524 int len, val; 525 526 HELP ("attr_get(\"/hw/cpunum/0\") ic_cpu_info.cpufq"); 527 528 len = sizeof (inv); 529 if (attr_get ("/hw/cpunum/0", INFO_LBL_DETAIL_INVENT, 530 (char *) &inv, &len, 0) == 0 531 && len == sizeof (inv) 532 && inv.ic_gen.ig_invclass == INV_PROCESSOR) 533 { 534 val = inv.ic_cpu_info.cpufq; 535 speed_cycletime = 1e-6 / val; 536 if (speed_option_verbose) 537 printf ("Using attr_get(\"/hw/cpunum/0\") ic_cpu_info.cpufq %d MHz for cycle time %.3g\n", val, speed_cycletime); 538 ret = 1; 539 } 540 #endif 541 return ret; 542 } 543 544 545 /* FreeBSD on i386 gives a line like the following at bootup, and which can 546 be read back from /var/run/dmesg.boot. 547 548 CPU: AMD Athlon(tm) Processor (755.29-MHz 686-class CPU) 549 CPU: Pentium 4 (1707.56-MHz 686-class CPU) 550 CPU: i486 DX4 (486-class CPU) 551 552 This is useful on FreeBSD 4.x, where there's no sysctl machdep.tsc_freq 553 or machdep.i586_freq. 554 555 It's better to use /var/run/dmesg.boot than to run /sbin/dmesg, since the 556 latter prints the current system message buffer, which is a limited size 557 and can wrap around if the system is up for a long time. */ 558 559 static int 560 freq_bsd_dmesg (int help) 561 { 562 FILE *fp; 563 char buf[256], *p; 564 double val; 565 int ret = 0; 566 int end; 567 568 HELP ("BSD /var/run/dmesg.boot file"); 569 570 if ((fp = fopen ("/var/run/dmesg.boot", "r")) != NULL) 571 { 572 while (fgets (buf, sizeof (buf), fp) != NULL) 573 { 574 if (memcmp (buf, "CPU:", 4) == 0) 575 { 576 for (p = buf; *p != '\0'; p++) 577 { 578 end = 0; 579 if (sscanf (p, "(%lf-MHz%n", &val, &end) == 1 && end != 0) 580 { 581 speed_cycletime = 1e-6 / val; 582 if (speed_option_verbose) 583 printf ("Using /var/run/dmesg.boot CPU: %.2f MHz for cycle time %.3g\n", val, speed_cycletime); 584 ret = 1; 585 break; 586 } 587 } 588 } 589 } 590 fclose (fp); 591 } 592 return ret; 593 } 594 595 596 /* "hinv -c processor" for IRIX. The following lines have been seen, 597 598 1 150 MHZ IP20 Processor 599 2 195 MHZ IP27 Processors 600 Processor 0: 500 MHZ IP35 601 602 This information is available from attr_get() on IRIX 6.5 (see above), 603 but on IRIX 6.2 it's not clear where to look, so fall back on 604 parsing. */ 605 606 static int 607 freq_irix_hinv (int help) 608 { 609 int ret = 0; 610 #if HAVE_POPEN 611 FILE *fp; 612 char buf[128]; 613 double val; 614 int nproc, end; 615 616 HELP ("IRIX \"hinv -c processor\" output"); 617 618 /* Error messages are sent to /dev/null in case hinv doesn't exist. The 619 brackets are necessary for some shells. */ 620 if ((fp = popen ("(hinv -c processor) 2>/dev/null", "r")) != NULL) 621 { 622 while (fgets (buf, sizeof (buf), fp) != NULL) 623 { 624 end = 0; 625 if (sscanf (buf, "Processor 0: %lf MHZ%n", &val, &end) == 1 626 && end != 0) 627 { 628 found: 629 speed_cycletime = 1e-6 / val; 630 if (speed_option_verbose) 631 printf ("Using hinv -c processor \"%.2f MHZ\" for cycle time %.3g\n", val, speed_cycletime); 632 ret = 1; 633 break; 634 } 635 end = 0; 636 if (sscanf (buf, "%d %lf MHZ%n", &nproc, &val, &end) == 2 637 && end != 0) 638 goto found; 639 } 640 pclose (fp); 641 } 642 #endif 643 return ret; 644 } 645 646 647 /* processor_info() for Solaris. "psrinfo" is the command-line interface to 648 this. "prtconf -vp" gives similar information. 649 650 Apple Darwin has a processor_info, but in an incompatible style. It 651 doesn't have <sys/processor.h>, so test for that. */ 652 653 static int 654 freq_processor_info (int help) 655 { 656 #if HAVE_PROCESSOR_INFO && HAVE_SYS_PROCESSOR_H 657 processor_info_t p; 658 int i, n, mhz = 0; 659 660 HELP ("processor_info() pi_clock"); 661 662 n = sysconf (_SC_NPROCESSORS_CONF); 663 for (i = 0; i < n; i++) 664 { 665 if (processor_info (i, &p) != 0) 666 continue; 667 if (p.pi_state != P_ONLINE) 668 continue; 669 670 if (mhz != 0 && p.pi_clock != mhz) 671 { 672 fprintf (stderr, 673 "freq_processor_info(): There's more than one CPU and they have different clock speeds\n"); 674 return 0; 675 } 676 677 mhz = p.pi_clock; 678 } 679 680 speed_cycletime = 1.0e-6 / (double) mhz; 681 682 if (speed_option_verbose) 683 printf ("Using processor_info() %d mhz for cycle time %.3g\n", 684 mhz, speed_cycletime); 685 return 1; 686 687 #else 688 return 0; 689 #endif 690 } 691 692 693 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY 694 static double 695 freq_measure_gettimeofday_one (void) 696 { 697 #define call_gettimeofday(t) gettimeofday (&(t), NULL) 698 #define timeval_tv_sec(t) ((t).tv_sec) 699 #define timeval_tv_usec(t) ((t).tv_usec) 700 FREQ_MEASURE_ONE ("gettimeofday", struct timeval, 701 call_gettimeofday, speed_cyclecounter, 702 timeval_tv_sec, timeval_tv_usec); 703 } 704 #endif 705 706 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE 707 static double 708 freq_measure_getrusage_one (void) 709 { 710 #define call_getrusage(t) getrusage (0, &(t)) 711 #define rusage_tv_sec(t) ((t).ru_utime.tv_sec) 712 #define rusage_tv_usec(t) ((t).ru_utime.tv_usec) 713 FREQ_MEASURE_ONE ("getrusage", struct rusage, 714 call_getrusage, speed_cyclecounter, 715 rusage_tv_sec, rusage_tv_usec); 716 } 717 #endif 718 719 720 /* MEASURE_MATCH is how many readings within MEASURE_TOLERANCE of each other 721 are required. This must be at least 2. */ 722 #define MEASURE_MAX_ATTEMPTS 20 723 #define MEASURE_TOLERANCE 1.005 /* 0.5% */ 724 #define MEASURE_MATCH 3 725 726 double 727 freq_measure (const char *name, double (*one) (void)) 728 { 729 double t[MEASURE_MAX_ATTEMPTS]; 730 int i, j; 731 732 for (i = 0; i < numberof (t); i++) 733 { 734 t[i] = (*one) (); 735 736 qsort (t, i+1, sizeof(t[0]), (qsort_function_t) double_cmp_ptr); 737 if (speed_option_verbose >= 3) 738 for (j = 0; j <= i; j++) 739 printf (" t[%d] is %.6g\n", j, t[j]); 740 741 for (j = 0; j+MEASURE_MATCH-1 <= i; j++) 742 { 743 if (t[j+MEASURE_MATCH-1] <= t[j] * MEASURE_TOLERANCE) 744 { 745 /* use the average of the range found */ 746 return (t[j+MEASURE_MATCH-1] + t[j]) / 2.0; 747 } 748 } 749 } 750 return -1.0; 751 } 752 753 static int 754 freq_measure_getrusage (int help) 755 { 756 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE 757 double cycletime; 758 759 if (! getrusage_microseconds_p ()) 760 return 0; 761 if (! cycles_works_p ()) 762 return 0; 763 764 HELP ("cycle counter measured with microsecond getrusage()"); 765 766 cycletime = freq_measure ("getrusage", freq_measure_getrusage_one); 767 if (cycletime == -1.0) 768 return 0; 769 770 speed_cycletime = cycletime; 771 if (speed_option_verbose) 772 printf ("Using getrusage() measured cycle counter %.4g (%.2f MHz)\n", 773 speed_cycletime, 1e-6/speed_cycletime); 774 return 1; 775 776 #else 777 return 0; 778 #endif 779 } 780 781 static int 782 freq_measure_gettimeofday (int help) 783 { 784 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY 785 double cycletime; 786 787 if (! gettimeofday_microseconds_p ()) 788 return 0; 789 if (! cycles_works_p ()) 790 return 0; 791 792 HELP ("cycle counter measured with microsecond gettimeofday()"); 793 794 cycletime = freq_measure ("gettimeofday", freq_measure_gettimeofday_one); 795 if (cycletime == -1.0) 796 return 0; 797 798 speed_cycletime = cycletime; 799 if (speed_option_verbose) 800 printf ("Using gettimeofday() measured cycle counter %.4g (%.2f MHz)\n", 801 speed_cycletime, 1e-6/speed_cycletime); 802 return 1; 803 #else 804 return 0; 805 #endif 806 } 807 808 809 /* Each function returns 1 if it succeeds in setting speed_cycletime, or 0 810 if not. 811 812 In general system call tests are first since they're fast, then file 813 tests, then tests running programs. Necessary exceptions to this rule 814 are noted. The measuring is last since it's time consuming, and rather 815 wasteful of cpu. */ 816 817 static int 818 freq_all (int help) 819 { 820 return 821 /* This should be first, so an environment variable can override 822 anything the system gives. */ 823 freq_environment (help) 824 825 || freq_attr_get_invent (help) 826 || freq_getsysinfo (help) 827 || freq_pstat_getprocessor (help) 828 || freq_sysctl_hw_model (help) 829 || freq_sysctl_hw_cpufrequency (help) 830 || freq_sysctlbyname_i586_freq (help) 831 || freq_sysctlbyname_tsc_freq (help) 832 833 /* SCO openunix 8 puts a dummy pi_clock==16 in processor_info, so be 834 sure to check /etc/hw before that function. */ 835 || freq_sco_etchw (help) 836 837 || freq_processor_info (help) 838 || freq_proc_cpuinfo (help) 839 || freq_bsd_dmesg (help) 840 || freq_irix_hinv (help) 841 || freq_sunos_sysinfo (help) 842 || freq_measure_getrusage (help) 843 || freq_measure_gettimeofday (help); 844 } 845 846 847 void 848 speed_cycletime_init (void) 849 { 850 static int attempted = 0; 851 852 if (attempted) 853 return; 854 attempted = 1; 855 856 if (freq_all (0)) 857 return; 858 859 if (speed_option_verbose) 860 printf ("CPU frequency couldn't be determined\n"); 861 } 862 863 864 void 865 speed_cycletime_fail (const char *str) 866 { 867 fprintf (stderr, "Measuring with: %s\n", speed_time_string); 868 fprintf (stderr, "%s,\n", str); 869 fprintf (stderr, "but none of the following are available,\n"); 870 freq_all (1); 871 abort (); 872 } 873 874 /* speed_time_init leaves speed_cycletime set to either 0.0 or 1.0 when the 875 CPU frequency is unknown. 0.0 is when the time base is in seconds, so 876 that's no good if cycles are wanted. 1.0 is when the time base is in 877 cycles, which conversely is no good if seconds are wanted. */ 878 void 879 speed_cycletime_need_cycles (void) 880 { 881 speed_time_init (); 882 if (speed_cycletime == 0.0) 883 speed_cycletime_fail 884 ("Need to know CPU frequency to give times in cycles"); 885 } 886 void 887 speed_cycletime_need_seconds (void) 888 { 889 speed_time_init (); 890 if (speed_cycletime == 1.0) 891 speed_cycletime_fail 892 ("Need to know CPU frequency to convert cycles to seconds"); 893 } 894