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