1 /* CPU frequency determination.
3 Copyright 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
5 This file is part of the GNU MP Library.
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 3 of the License, or (at your
10 option) any later version.
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.
17 You should have received a copy of the GNU Lesser General Public License
18 along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */
21 /* Currently we don't get a CPU frequency on the following systems,
23 alphaev5-cray-unicosmk2.0.6.X
24 times() has been seen at 13.33 ns (75 MHz), which is probably not the
25 cpu frequency. Measuring the cycle counter against that would be
26 possible though. But currently we don't use the cycle counter due to
27 unicos having int==8bytes where tune/alpha.asm assumes int==4bytes.
29 m68040-unknown-netbsd1.4.1
30 Not sure if the system even knows the cpu frequency. There's no
31 cycle counter to measure, though we could perhaps make a loop taking
32 a known number of cycles and measure that.
36 powerpc604-ibm-aix4.3.1.0
37 powerpc604-ibm-aix4.3.3.0
38 powerpc630-ibm-aix4.3.3.0
39 powerpc-unknown-netbsd1.6
40 Don't know where any info hides on these. mftb is not related to the
41 cpu frequency so doesn't help.
43 sparc-unknown-linux-gnu [maybe]
44 Don't know where any info hides on this.
47 The times() call seems to be for instance 2.22 nanoseconds, which
48 might be the cpu frequency (450 mhz), but need to confirm that.
55 #include <invent.h> /* for IRIX invent_cpuinfo_t */
59 #include <stdlib.h> /* for getenv, qsort */
60 #include <string.h> /* for memcmp */
63 #include <unistd.h> /* for sysconf */
66 #include <sys/types.h>
68 #if HAVE_SYS_ATTRIBUTES_H
69 #include <sys/attributes.h> /* for IRIX attr_get(), needs sys/types.h */
72 #if HAVE_SYS_IOGRAPH_H
73 #include <sys/iograph.h> /* for IRIX INFO_LBL_DETAIL_INVENT */
76 #if HAVE_SYS_PARAM_H /* for constants needed by NetBSD <sys/sysctl.h> */
77 #include <sys/param.h> /* and needed by HPUX <sys/pstat.h> */
81 #include <sys/pstat.h> /* for HPUX pstat_getprocessor() */
85 #include <sys/sysctl.h> /* for sysctlbyname() */
88 #if TIME_WITH_SYS_TIME
89 # include <sys/time.h> /* for struct timeval */
93 # include <sys/time.h>
99 #if HAVE_SYS_RESOURCE_H
100 #include <sys/resource.h> /* for struct rusage */
103 #if HAVE_SYS_PROCESSOR_H
104 #include <sys/processor.h> /* for solaris processor_info_t */
107 /* On AIX 5.1 with gcc 2.9-aix51-020209 in -maix64 mode, <sys/sysinfo.h>
108 gets an error about "fill" in "struct cpuinfo" having a negative size,
109 apparently due to __64BIT_KERNEL not being defined because _KERNEL is not
110 defined. Avoid this file if we don't actually need it, which we don't on
111 AIX since there's no getsysinfo there. */
112 #if HAVE_SYS_SYSINFO_H && HAVE_GETSYSINFO
113 #include <sys/sysinfo.h> /* for OSF getsysinfo */
116 #if HAVE_MACHINE_HAL_SYSINFO_H
117 #include <machine/hal_sysinfo.h> /* for OSF GSI_CPU_INFO, struct cpu_info */
120 /* Remove definitions from NetBSD <sys/param.h>, to avoid conflicts with
130 #include "gmp-impl.h"
138 printf (" - %s\n", str); \
143 /* GMP_CPU_FREQUENCY environment variable. Should be in Hertz and can be
144 floating point, for example "450e6". */
146 freq_environment (int help)
150 HELP ("environment variable GMP_CPU_FREQUENCY (in Hertz)");
152 e = getenv ("GMP_CPU_FREQUENCY");
156 speed_cycletime = 1.0 / atof (e);
158 if (speed_option_verbose)
159 printf ("Using GMP_CPU_FREQUENCY %.2f for cycle time %.3g\n",
160 atof (e), speed_cycletime);
166 /* getsysinfo is available on OSF, or 4.0 and up at least.
167 The man page (on 4.0) suggests a 0 return indicates information not
168 available, but that seems to be the normal return for GSI_CPU_INFO. */
170 freq_getsysinfo (int help)
176 HELP ("getsysinfo() GSI_CPU_INFO");
179 if (getsysinfo (GSI_CPU_INFO, (caddr_t) &c, sizeof (c),
180 &start, NULL, NULL) != -1)
182 speed_cycletime = 1e-6 / (double) c.mhz;
183 if (speed_option_verbose)
184 printf ("Using getsysinfo() GSI_CPU_INFO %u for cycle time %.3g\n",
185 c.mhz, speed_cycletime);
193 /* In HPUX 10 and up, pstat_getprocessor() psp_iticksperclktick is the
194 number of CPU cycles (ie. the CR16 register) per CLK_TCK. HPUX 9 doesn't
195 have that field in pst_processor though, and has no apparent
199 freq_pstat_getprocessor (int help)
201 #if HAVE_PSTAT_GETPROCESSOR && HAVE_PSP_ITICKSPERCLKTICK
202 struct pst_processor p;
204 HELP ("pstat_getprocessor() psp_iticksperclktick");
206 if (pstat_getprocessor (&p, sizeof(p), 1, 0) != -1)
209 speed_cycletime = 1.0 / (c * p.psp_iticksperclktick);
210 if (speed_option_verbose)
211 printf ("Using pstat_getprocessor() psp_iticksperclktick %lu and clk_tck %ld for cycle time %.3g\n",
212 (unsigned long) p.psp_iticksperclktick, c,
221 /* i386 FreeBSD 2.2.8 sysctlbyname machdep.i586_freq is in Hertz.
222 There's no obvious defines available to get this from plain sysctl. */
224 freq_sysctlbyname_i586_freq (int help)
226 #if HAVE_SYSCTLBYNAME
230 HELP ("sysctlbyname() machdep.i586_freq");
233 if (sysctlbyname ("machdep.i586_freq", &val, &size, NULL, 0) == 0
234 && size == sizeof(val))
236 speed_cycletime = 1.0 / (double) val;
237 if (speed_option_verbose)
238 printf ("Using sysctlbyname() machdep.i586_freq %u for cycle time %.3g\n",
239 val, speed_cycletime);
247 /* i368 FreeBSD 3.3 sysctlbyname machdep.tsc_freq is in Hertz.
248 There's no obvious defines to get this from plain sysctl. */
251 freq_sysctlbyname_tsc_freq (int help)
253 #if HAVE_SYSCTLBYNAME
257 HELP ("sysctlbyname() machdep.tsc_freq");
260 if (sysctlbyname ("machdep.tsc_freq", &val, &size, NULL, 0) == 0
261 && size == sizeof(val))
263 speed_cycletime = 1.0 / (double) val;
264 if (speed_option_verbose)
265 printf ("Using sysctlbyname() machdep.tsc_freq %u for cycle time %.3g\n",
266 val, speed_cycletime);
274 /* Apple powerpc Darwin 1.3 sysctl hw.cpufrequency is in hertz. For some
275 reason only seems to be available from sysctl(), not sysctlbyname(). */
278 freq_sysctl_hw_cpufrequency (int help)
280 #if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_CPU_FREQ)
285 HELP ("sysctl() hw.cpufrequency");
288 mib[1] = HW_CPU_FREQ;
290 if (sysctl (mib, 2, &val, &size, NULL, 0) == 0)
292 speed_cycletime = 1.0 / (double) val;
293 if (speed_option_verbose)
294 printf ("Using sysctl() hw.cpufrequency %u for cycle time %.3g\n",
295 val, speed_cycletime);
303 /* The following ssyctl hw.model strings have been observed,
305 Alpha FreeBSD 4.1: Digital AlphaPC 164LX 599 MHz
306 NetBSD 1.4: Digital AlphaPC 164LX 599 MHz
307 NetBSD 1.6.1: CY7C601 @ 40 MHz, TMS390C602A FPU
309 NetBSD 1.4 doesn't seem to have sysctlbyname, so sysctl() is used. */
312 freq_sysctl_hw_model (int help)
314 #if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_MODEL)
322 HELP ("sysctl() hw.model");
327 if (sysctl (mib, 2, str, &size, NULL, 0) == 0)
329 for (p = str; *p != '\0'; p++)
332 if (sscanf (p, "%u MHz%n", &val, &end) == 1 && end != 0)
334 speed_cycletime = 1e-6 / (double) val;
335 if (speed_option_verbose)
336 printf ("Using sysctl() hw.model %u for cycle time %.3g\n",
337 val, speed_cycletime);
347 /* /proc/cpuinfo for linux kernel.
349 Linux doesn't seem to have any system call to get the CPU frequency, at
350 least not in 2.0.x or 2.2.x, so it's necessary to read /proc/cpuinfo.
352 i386 2.0.36 - "bogomips" is the CPU frequency.
354 i386 2.2.13 - has both "cpu MHz" and "bogomips", and it's "cpu MHz" which
357 alpha 2.2.5 - "cycle frequency [Hz]" seems to be right, "BogoMIPS" is
358 very slightly different.
360 alpha 2.2.18pre21 - "cycle frequency [Hz]" is 0 on at least one system,
361 "BogoMIPS" seems near enough.
363 powerpc 2.2.19 - "clock" is the frequency, bogomips is something weird
367 freq_proc_cpuinfo (int help)
375 HELP ("linux kernel /proc/cpuinfo file, cpu MHz or bogomips");
377 if ((fp = fopen ("/proc/cpuinfo", "r")) != NULL)
379 while (fgets (buf, sizeof (buf), fp) != NULL)
381 if (sscanf (buf, "cycle frequency [Hz] : %lf", &val) == 1
384 speed_cycletime = 1.0 / val;
385 if (speed_option_verbose)
386 printf ("Using /proc/cpuinfo \"cycle frequency\" %.2f for cycle time %.3g\n", val, speed_cycletime);
390 if (sscanf (buf, "cpu MHz : %lf\n", &val) == 1)
392 speed_cycletime = 1e-6 / val;
393 if (speed_option_verbose)
394 printf ("Using /proc/cpuinfo \"cpu MHz\" %.2f for cycle time %.3g\n", val, speed_cycletime);
399 if (sscanf (buf, "clock : %lfMHz\n%n", &val, &end) == 1 && end != 0)
401 speed_cycletime = 1e-6 / val;
402 if (speed_option_verbose)
403 printf ("Using /proc/cpuinfo \"clock\" %.2f for cycle time %.3g\n", val, speed_cycletime);
407 if (sscanf (buf, "bogomips : %lf\n", &val) == 1
408 || sscanf (buf, "BogoMIPS : %lf\n", &val) == 1)
410 speed_cycletime = 1e-6 / val;
411 if (speed_option_verbose)
412 printf ("Using /proc/cpuinfo \"bogomips\" %.2f for cycle time %.3g\n", val, speed_cycletime);
423 /* /bin/sysinfo for SunOS 4.
424 Prints a line like: cpu0 is a "75 MHz TI,TMS390Z55" CPU */
426 freq_sunos_sysinfo (int help)
435 HELP ("SunOS /bin/sysinfo program output, cpu0");
437 /* Error messages are sent to /dev/null in case /bin/sysinfo doesn't
438 exist. The brackets are necessary for some shells. */
439 if ((fp = popen ("(/bin/sysinfo) 2>/dev/null", "r")) != NULL)
441 while (fgets (buf, sizeof (buf), fp) != NULL)
444 if (sscanf (buf, " cpu0 is a \"%lf MHz%n", &val, &end) == 1
447 speed_cycletime = 1e-6 / val;
448 if (speed_option_verbose)
449 printf ("Using /bin/sysinfo \"cpu0 MHz\" %.2f for cycle time %.3g\n", val, speed_cycletime);
461 /* "/etc/hw -r cpu" for SCO OpenUnix 8, printing a line like
462 The speed of the CPU is approximately 450Mhz
465 freq_sco_etchw (int help)
474 HELP ("SCO /etc/hw program output");
476 /* Error messages are sent to /dev/null in case /etc/hw doesn't exist.
477 The brackets are necessary for some shells. */
478 if ((fp = popen ("(/etc/hw -r cpu) 2>/dev/null", "r")) != NULL)
480 while (fgets (buf, sizeof (buf), fp) != NULL)
483 if (sscanf (buf, " The speed of the CPU is approximately %lfMhz%n",
484 &val, &end) == 1 && end != 0)
486 speed_cycletime = 1e-6 / val;
487 if (speed_option_verbose)
488 printf ("Using /etc/hw %.2f MHz, for cycle time %.3g\n",
489 val, speed_cycletime);
501 /* attr_get("/hw/cpunum/0",INFO_LBL_DETAIL_INVENT) ic_cpu_info.cpufq for
502 IRIX 6.5. Past versions don't have INFO_LBL_DETAIL_INVENT,
503 invent_cpuinfo_t, or /hw/cpunum/0.
505 The same information is available from the "hinv -c processor" command,
506 but it seems better to make a system call where possible. */
509 freq_attr_get_invent (int help)
512 #if HAVE_ATTR_GET && HAVE_INVENT_H && defined (INFO_LBL_DETAIL_INVENT)
513 invent_cpuinfo_t inv;
516 HELP ("attr_get(\"/hw/cpunum/0\") ic_cpu_info.cpufq");
519 if (attr_get ("/hw/cpunum/0", INFO_LBL_DETAIL_INVENT,
520 (char *) &inv, &len, 0) == 0
521 && len == sizeof (inv)
522 && inv.ic_gen.ig_invclass == INV_PROCESSOR)
524 val = inv.ic_cpu_info.cpufq;
525 speed_cycletime = 1e-6 / val;
526 if (speed_option_verbose)
527 printf ("Using attr_get(\"/hw/cpunum/0\") ic_cpu_info.cpufq %d MHz for cycle time %.3g\n", val, speed_cycletime);
535 /* FreeBSD on i386 gives a line like the following at bootup, and which can
536 be read back from /var/run/dmesg.boot.
538 CPU: AMD Athlon(tm) Processor (755.29-MHz 686-class CPU)
539 CPU: Pentium 4 (1707.56-MHz 686-class CPU)
540 CPU: i486 DX4 (486-class CPU)
542 This is useful on FreeBSD 4.x, where there's no sysctl machdep.tsc_freq
543 or machdep.i586_freq.
545 It's better to use /var/run/dmesg.boot than to run /sbin/dmesg, since the
546 latter prints the current system message buffer, which is a limited size
547 and can wrap around if the system is up for a long time. */
550 freq_bsd_dmesg (int help)
558 HELP ("BSD /var/run/dmesg.boot file");
560 if ((fp = fopen ("/var/run/dmesg.boot", "r")) != NULL)
562 while (fgets (buf, sizeof (buf), fp) != NULL)
564 if (memcmp (buf, "CPU:", 4) == 0)
566 for (p = buf; *p != '\0'; p++)
569 if (sscanf (p, "(%lf-MHz%n", &val, &end) == 1 && end != 0)
571 speed_cycletime = 1e-6 / val;
572 if (speed_option_verbose)
573 printf ("Using /var/run/dmesg.boot CPU: %.2f MHz for cycle time %.3g\n", val, speed_cycletime);
586 /* "hinv -c processor" for IRIX. The following lines have been seen,
588 1 150 MHZ IP20 Processor
589 2 195 MHZ IP27 Processors
590 Processor 0: 500 MHZ IP35
592 This information is available from attr_get() on IRIX 6.5 (see above),
593 but on IRIX 6.2 it's not clear where to look, so fall back on
597 freq_irix_hinv (int help)
606 HELP ("IRIX \"hinv -c processor\" output");
608 /* Error messages are sent to /dev/null in case hinv doesn't exist. The
609 brackets are necessary for some shells. */
610 if ((fp = popen ("(hinv -c processor) 2>/dev/null", "r")) != NULL)
612 while (fgets (buf, sizeof (buf), fp) != NULL)
615 if (sscanf (buf, "Processor 0: %lf MHZ%n", &val, &end) == 1
619 speed_cycletime = 1e-6 / val;
620 if (speed_option_verbose)
621 printf ("Using hinv -c processor \"%.2f MHZ\" for cycle time %.3g\n", val, speed_cycletime);
626 if (sscanf (buf, "%d %lf MHZ%n", &nproc, &val, &end) == 2
637 /* processor_info() for Solaris. "psrinfo" is the command-line interface to
638 this. "prtconf -vp" gives similar information.
640 Apple Darwin has a processor_info, but in an incompatible style. It
641 doesn't have <sys/processor.h>, so test for that. */
644 freq_processor_info (int help)
646 #if HAVE_PROCESSOR_INFO && HAVE_SYS_PROCESSOR_H
650 HELP ("processor_info() pi_clock");
652 n = sysconf (_SC_NPROCESSORS_CONF);
653 for (i = 0; i < n; i++)
655 if (processor_info (i, &p) != 0)
657 if (p.pi_state != P_ONLINE)
660 if (mhz != 0 && p.pi_clock != mhz)
663 "freq_processor_info(): There's more than one CPU and they have different clock speeds\n");
670 speed_cycletime = 1.0e-6 / (double) mhz;
672 if (speed_option_verbose)
673 printf ("Using processor_info() %d mhz for cycle time %.3g\n",
674 mhz, speed_cycletime);
683 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY
685 freq_measure_gettimeofday_one (void)
687 #define call_gettimeofday(t) gettimeofday (&(t), NULL)
688 #define timeval_tv_sec(t) ((t).tv_sec)
689 #define timeval_tv_usec(t) ((t).tv_usec)
690 FREQ_MEASURE_ONE ("gettimeofday", struct timeval,
691 call_gettimeofday, speed_cyclecounter,
692 timeval_tv_sec, timeval_tv_usec);
696 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE
698 freq_measure_getrusage_one (void)
700 #define call_getrusage(t) getrusage (0, &(t))
701 #define rusage_tv_sec(t) ((t).ru_utime.tv_sec)
702 #define rusage_tv_usec(t) ((t).ru_utime.tv_usec)
703 FREQ_MEASURE_ONE ("getrusage", struct rusage,
704 call_getrusage, speed_cyclecounter,
705 rusage_tv_sec, rusage_tv_usec);
710 /* MEASURE_MATCH is how many readings within MEASURE_TOLERANCE of each other
711 are required. This must be at least 2. */
712 #define MEASURE_MAX_ATTEMPTS 20
713 #define MEASURE_TOLERANCE 1.005 /* 0.5% */
714 #define MEASURE_MATCH 3
717 freq_measure (const char *name, double (*one) (void))
719 double t[MEASURE_MAX_ATTEMPTS];
722 for (i = 0; i < numberof (t); i++)
726 qsort (t, i+1, sizeof(t[0]), (qsort_function_t) double_cmp_ptr);
727 if (speed_option_verbose >= 3)
728 for (j = 0; j <= i; j++)
729 printf (" t[%d] is %.6g\n", j, t[j]);
731 for (j = 0; j+MEASURE_MATCH-1 <= i; j++)
733 if (t[j+MEASURE_MATCH-1] <= t[j] * MEASURE_TOLERANCE)
735 /* use the average of the range found */
736 return (t[j+MEASURE_MATCH-1] + t[j]) / 2.0;
744 freq_measure_getrusage (int help)
746 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE
749 if (! getrusage_microseconds_p ())
751 if (! cycles_works_p ())
754 HELP ("cycle counter measured with microsecond getrusage()");
756 cycletime = freq_measure ("getrusage", freq_measure_getrusage_one);
757 if (cycletime == -1.0)
760 speed_cycletime = cycletime;
761 if (speed_option_verbose)
762 printf ("Using getrusage() measured cycle counter %.4g (%.2f MHz)\n",
763 speed_cycletime, 1e-6/speed_cycletime);
772 freq_measure_gettimeofday (int help)
774 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY
777 if (! gettimeofday_microseconds_p ())
779 if (! cycles_works_p ())
782 HELP ("cycle counter measured with microsecond gettimeofday()");
784 cycletime = freq_measure ("gettimeofday", freq_measure_gettimeofday_one);
785 if (cycletime == -1.0)
788 speed_cycletime = cycletime;
789 if (speed_option_verbose)
790 printf ("Using gettimeofday() measured cycle counter %.4g (%.2f MHz)\n",
791 speed_cycletime, 1e-6/speed_cycletime);
799 /* Each function returns 1 if it succeeds in setting speed_cycletime, or 0
802 In general system call tests are first since they're fast, then file
803 tests, then tests running programs. Necessary exceptions to this rule
804 are noted. The measuring is last since it's time consuming, and rather
811 /* This should be first, so an environment variable can override
812 anything the system gives. */
813 freq_environment (help)
815 || freq_attr_get_invent (help)
816 || freq_getsysinfo (help)
817 || freq_pstat_getprocessor (help)
818 || freq_sysctl_hw_model (help)
819 || freq_sysctl_hw_cpufrequency (help)
820 || freq_sysctlbyname_i586_freq (help)
821 || freq_sysctlbyname_tsc_freq (help)
823 /* SCO openunix 8 puts a dummy pi_clock==16 in processor_info, so be
824 sure to check /etc/hw before that function. */
825 || freq_sco_etchw (help)
827 || freq_processor_info (help)
828 || freq_proc_cpuinfo (help)
829 || freq_bsd_dmesg (help)
830 || freq_irix_hinv (help)
831 || freq_sunos_sysinfo (help)
832 || freq_measure_getrusage (help)
833 || freq_measure_gettimeofday (help);
838 speed_cycletime_init (void)
840 static int attempted = 0;
849 if (speed_option_verbose)
850 printf ("CPU frequency couldn't be determined\n");
855 speed_cycletime_fail (const char *str)
857 fprintf (stderr, "Measuring with: %s\n", speed_time_string);
858 fprintf (stderr, "%s,\n", str);
859 fprintf (stderr, "but none of the following are available,\n");
864 /* speed_time_init leaves speed_cycletime set to either 0.0 or 1.0 when the
865 CPU frequency is unknown. 0.0 is when the time base is in seconds, so
866 that's no good if cycles are wanted. 1.0 is when the time base is in
867 cycles, which conversely is no good if seconds are wanted. */
869 speed_cycletime_need_cycles (void)
872 if (speed_cycletime == 0.0)
874 ("Need to know CPU frequency to give times in cycles");
877 speed_cycletime_need_seconds (void)
880 if (speed_cycletime == 1.0)
882 ("Need to know CPU frequency to convert cycles to seconds");