blob: ee385064782a3ed56b1407e9036a32d9e35d94cf [file] [log] [blame]
Austin Schuhdace2a62020-08-18 10:56:48 -07001/* CPU frequency determination.
2
3Copyright 1999-2004 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it 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
14or
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
20or both in parallel, as here.
21
22The GNU MP Library is distributed in the hope that it will be useful, but
23WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25for more details.
26
27You should have received copies of the GNU General Public License and the
28GNU Lesser General Public License along with the GNU MP Library. If not,
29see 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". */
155static int
156freq_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. */
179static int
180freq_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
208static int
209freq_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. */
233static int
234freq_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
260static int
261freq_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
287static int
288freq_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
321static int
322freq_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
376static int
377freq_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 */
435static int
436freq_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 */
474static int
475freq_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
518static int
519freq_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
559static int
560freq_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
606static int
607freq_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
653static int
654freq_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
694static double
695freq_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
707static double
708freq_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
726double
727freq_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
753static int
754freq_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
781static int
782freq_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
817static int
818freq_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
847void
848speed_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
864void
865speed_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. */
878void
879speed_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}
886void
887speed_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}