Tizen 2.1 base
[external/gmp.git] / tune / freq.c
1 /* CPU frequency determination.
2
3 Copyright 1999, 2000, 2001, 2002, 2003, 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 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.
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.  If not, see http://www.gnu.org/licenses/.  */
19
20
21 /* Currently we don't get a CPU frequency on the following systems,
22
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.
28
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.
33
34    power-ibm-aix4.2.1.0
35    power2-ibm-aix4.3.1.0
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.
42
43    sparc-unknown-linux-gnu [maybe]
44        Don't know where any info hides on this.
45
46    t90-cray-unicos10.0.X
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.
49
50 */
51
52 #include "config.h"
53
54 #if HAVE_INVENT_H
55 #include <invent.h> /* for IRIX invent_cpuinfo_t */
56 #endif
57
58 #include <stdio.h>
59 #include <stdlib.h> /* for getenv, qsort */
60 #include <string.h> /* for memcmp */
61
62 #if HAVE_UNISTD_H
63 #include <unistd.h> /* for sysconf */
64 #endif
65
66 #include <sys/types.h>
67
68 #if HAVE_SYS_ATTRIBUTES_H
69 #include <sys/attributes.h>   /* for IRIX attr_get(), needs sys/types.h */
70 #endif
71
72 #if HAVE_SYS_IOGRAPH_H
73 #include <sys/iograph.h>      /* for IRIX INFO_LBL_DETAIL_INVENT */
74 #endif
75
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> */
78 #endif
79
80 #if HAVE_SYS_PSTAT_H
81 #include <sys/pstat.h>   /* for HPUX pstat_getprocessor() */
82 #endif
83
84 #if HAVE_SYS_SYSCTL_H
85 #include <sys/sysctl.h>  /* for sysctlbyname() */
86 #endif
87
88 #if TIME_WITH_SYS_TIME
89 # include <sys/time.h>  /* for struct timeval */
90 # include <time.h>
91 #else
92 # if HAVE_SYS_TIME_H
93 #  include <sys/time.h>
94 # else
95 #  include <time.h>
96 # endif
97 #endif
98
99 #if HAVE_SYS_RESOURCE_H
100 #include <sys/resource.h>  /* for struct rusage */
101 #endif
102
103 #if HAVE_SYS_PROCESSOR_H
104 #include <sys/processor.h>  /* for solaris processor_info_t */
105 #endif
106
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 */
114 #endif
115
116 #if HAVE_MACHINE_HAL_SYSINFO_H
117 #include <machine/hal_sysinfo.h>  /* for OSF GSI_CPU_INFO, struct cpu_info */
118 #endif
119
120 /* Remove definitions from NetBSD <sys/param.h>, to avoid conflicts with
121    gmp-impl.h. */
122 #ifdef MIN
123 #undef MIN
124 #endif
125 #ifdef MAX
126 #undef MAX
127 #endif
128
129 #include "gmp.h"
130 #include "gmp-impl.h"
131
132 #include "speed.h"
133
134
135 #define HELP(str)                       \
136   if (help)                             \
137     {                                   \
138       printf ("    - %s\n", str);       \
139       return 0;                         \
140     }
141
142
143 /* GMP_CPU_FREQUENCY environment variable.  Should be in Hertz and can be
144    floating point, for example "450e6". */
145 static int
146 freq_environment (int help)
147 {
148   char  *e;
149
150   HELP ("environment variable GMP_CPU_FREQUENCY (in Hertz)");
151
152   e = getenv ("GMP_CPU_FREQUENCY");
153   if (e == NULL)
154     return 0;
155
156   speed_cycletime = 1.0 / atof (e);
157
158   if (speed_option_verbose)
159     printf ("Using GMP_CPU_FREQUENCY %.2f for cycle time %.3g\n",
160             atof (e), speed_cycletime);
161
162   return 1;
163 }
164
165
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.  */
169 static int
170 freq_getsysinfo (int help)
171 {
172 #if HAVE_GETSYSINFO
173   struct cpu_info  c;
174   int              start;
175
176   HELP ("getsysinfo() GSI_CPU_INFO");
177
178   start = 0;
179   if (getsysinfo (GSI_CPU_INFO, (caddr_t) &c, sizeof (c),
180                   &start, NULL, NULL) != -1)
181     {
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);
186       return 1;
187     }
188 #endif
189   return 0;
190 }
191
192
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
196    equivalent.  */
197
198 static int
199 freq_pstat_getprocessor (int help)
200 {
201 #if HAVE_PSTAT_GETPROCESSOR && HAVE_PSP_ITICKSPERCLKTICK
202   struct pst_processor  p;
203
204   HELP ("pstat_getprocessor() psp_iticksperclktick");
205
206   if (pstat_getprocessor (&p, sizeof(p), 1, 0) != -1)
207     {
208       long  c = clk_tck();
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,
213                 speed_cycletime);
214       return 1;
215     }
216 #endif
217   return 0;
218 }
219
220
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.  */
223 static int
224 freq_sysctlbyname_i586_freq (int help)
225 {
226 #if HAVE_SYSCTLBYNAME
227   unsigned  val;
228   size_t    size;
229
230   HELP ("sysctlbyname() machdep.i586_freq");
231
232   size = sizeof(val);
233   if (sysctlbyname ("machdep.i586_freq", &val, &size, NULL, 0) == 0
234       && size == sizeof(val))
235     {
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);
240       return 1;
241     }
242 #endif
243   return 0;
244 }
245
246
247 /* i368 FreeBSD 3.3 sysctlbyname machdep.tsc_freq is in Hertz.
248    There's no obvious defines to get this from plain sysctl.  */
249
250 static int
251 freq_sysctlbyname_tsc_freq (int help)
252 {
253 #if HAVE_SYSCTLBYNAME
254   unsigned  val;
255   size_t    size;
256
257   HELP ("sysctlbyname() machdep.tsc_freq");
258
259   size = sizeof(val);
260   if (sysctlbyname ("machdep.tsc_freq", &val, &size, NULL, 0) == 0
261       && size == sizeof(val))
262     {
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);
267       return 1;
268     }
269 #endif
270   return 0;
271 }
272
273
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().  */
276
277 static int
278 freq_sysctl_hw_cpufrequency (int help)
279 {
280 #if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_CPU_FREQ)
281   int       mib[2];
282   unsigned  val;
283   size_t    size;
284
285   HELP ("sysctl() hw.cpufrequency");
286
287   mib[0] = CTL_HW;
288   mib[1] = HW_CPU_FREQ;
289   size = sizeof(val);
290   if (sysctl (mib, 2, &val, &size, NULL, 0) == 0)
291     {
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);
296       return 1;
297     }
298 #endif
299   return 0;
300 }
301
302
303 /* The following ssyctl hw.model strings have been observed,
304
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
308
309    NetBSD 1.4 doesn't seem to have sysctlbyname, so sysctl() is used.  */
310
311 static int
312 freq_sysctl_hw_model (int help)
313 {
314 #if HAVE_SYSCTL && defined (CTL_HW) && defined (HW_MODEL)
315   int       mib[2];
316   char      str[128];
317   unsigned  val;
318   size_t    size;
319   char      *p;
320   int       end;
321
322   HELP ("sysctl() hw.model");
323
324   mib[0] = CTL_HW;
325   mib[1] = HW_MODEL;
326   size = sizeof(str);
327   if (sysctl (mib, 2, str, &size, NULL, 0) == 0)
328     {
329       for (p = str; *p != '\0'; p++)
330         {
331           end = 0;
332           if (sscanf (p, "%u MHz%n", &val, &end) == 1 && end != 0)
333             {
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);
338               return 1;
339             }
340         }
341     }
342 #endif
343   return 0;
344 }
345
346
347 /* /proc/cpuinfo for linux kernel.
348
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.
351
352    i386 2.0.36 - "bogomips" is the CPU frequency.
353
354    i386 2.2.13 - has both "cpu MHz" and "bogomips", and it's "cpu MHz" which
355                  is the frequency.
356
357    alpha 2.2.5 - "cycle frequency [Hz]" seems to be right, "BogoMIPS" is
358                  very slightly different.
359
360    alpha 2.2.18pre21 - "cycle frequency [Hz]" is 0 on at least one system,
361                  "BogoMIPS" seems near enough.
362
363    powerpc 2.2.19 - "clock" is the frequency, bogomips is something weird
364   */
365
366 static int
367 freq_proc_cpuinfo (int help)
368 {
369   FILE    *fp;
370   char    buf[128];
371   double  val;
372   int     ret = 0;
373   int     end;
374
375   HELP ("linux kernel /proc/cpuinfo file, cpu MHz or bogomips");
376
377   if ((fp = fopen ("/proc/cpuinfo", "r")) != NULL)
378     {
379       while (fgets (buf, sizeof (buf), fp) != NULL)
380         {
381           if (sscanf (buf, "cycle frequency [Hz]    : %lf", &val) == 1
382               && val != 0.0)
383             {
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);
387               ret = 1;
388               break;
389             }
390           if (sscanf (buf, "cpu MHz : %lf\n", &val) == 1)
391             {
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);
395               ret = 1;
396               break;
397             }
398           end = 0;
399           if (sscanf (buf, "clock : %lfMHz\n%n", &val, &end) == 1 && end != 0)
400             {
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);
404               ret = 1;
405               break;
406             }
407           if (sscanf (buf, "bogomips : %lf\n", &val) == 1
408               || sscanf (buf, "BogoMIPS : %lf\n", &val) == 1)
409             {
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);
413               ret = 1;
414               break;
415             }
416         }
417       fclose (fp);
418     }
419   return ret;
420 }
421
422
423 /* /bin/sysinfo for SunOS 4.
424    Prints a line like: cpu0 is a "75 MHz TI,TMS390Z55" CPU */
425 static int
426 freq_sunos_sysinfo (int help)
427 {
428   int     ret = 0;
429 #if HAVE_POPEN
430   FILE    *fp;
431   char    buf[128];
432   double  val;
433   int     end;
434
435   HELP ("SunOS /bin/sysinfo program output, cpu0");
436
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)
440     {
441       while (fgets (buf, sizeof (buf), fp) != NULL)
442         {
443           end = 0;
444           if (sscanf (buf, " cpu0 is a \"%lf MHz%n", &val, &end) == 1
445               && end != 0)
446             {
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);
450               ret = 1;
451               break;
452             }
453         }
454       pclose (fp);
455     }
456 #endif
457   return ret;
458 }
459
460
461 /* "/etc/hw -r cpu" for SCO OpenUnix 8, printing a line like
462         The speed of the CPU is approximately 450Mhz
463  */
464 static int
465 freq_sco_etchw (int help)
466 {
467   int     ret = 0;
468 #if HAVE_POPEN
469   FILE    *fp;
470   char    buf[128];
471   double  val;
472   int     end;
473
474   HELP ("SCO /etc/hw program output");
475
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)
479     {
480       while (fgets (buf, sizeof (buf), fp) != NULL)
481         {
482           end = 0;
483           if (sscanf (buf, " The speed of the CPU is approximately %lfMhz%n",
484                       &val, &end) == 1 && end != 0)
485             {
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);
490               ret = 1;
491               break;
492             }
493         }
494       pclose (fp);
495     }
496 #endif
497   return ret;
498 }
499
500
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.
504
505    The same information is available from the "hinv -c processor" command,
506    but it seems better to make a system call where possible. */
507
508 static int
509 freq_attr_get_invent (int help)
510 {
511   int     ret = 0;
512 #if HAVE_ATTR_GET && HAVE_INVENT_H && defined (INFO_LBL_DETAIL_INVENT)
513   invent_cpuinfo_t  inv;
514   int               len, val;
515
516   HELP ("attr_get(\"/hw/cpunum/0\") ic_cpu_info.cpufq");
517
518   len = sizeof (inv);
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)
523     {
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);
528       ret = 1;
529     }
530 #endif
531   return ret;
532 }
533
534
535 /* FreeBSD on i386 gives a line like the following at bootup, and which can
536    be read back from /var/run/dmesg.boot.
537
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)
541
542    This is useful on FreeBSD 4.x, where there's no sysctl machdep.tsc_freq
543    or machdep.i586_freq.
544
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.  */
548
549 static int
550 freq_bsd_dmesg (int help)
551 {
552   FILE    *fp;
553   char    buf[256], *p;
554   double  val;
555   int     ret = 0;
556   int     end;
557
558   HELP ("BSD /var/run/dmesg.boot file");
559
560   if ((fp = fopen ("/var/run/dmesg.boot", "r")) != NULL)
561     {
562       while (fgets (buf, sizeof (buf), fp) != NULL)
563         {
564           if (memcmp (buf, "CPU:", 4) == 0)
565             {
566               for (p = buf; *p != '\0'; p++)
567                 {
568                   end = 0;
569                   if (sscanf (p, "(%lf-MHz%n", &val, &end) == 1 && end != 0)
570                     {
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);
574                       ret = 1;
575                       break;
576                     }
577                 }
578             }
579         }
580       fclose (fp);
581     }
582   return ret;
583 }
584
585
586 /* "hinv -c processor" for IRIX.  The following lines have been seen,
587
588               1 150 MHZ IP20 Processor
589               2 195 MHZ IP27 Processors
590               Processor 0: 500 MHZ IP35
591
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
594    parsing.  */
595
596 static int
597 freq_irix_hinv (int help)
598 {
599   int     ret = 0;
600 #if HAVE_POPEN
601   FILE    *fp;
602   char    buf[128];
603   double  val;
604   int     nproc, end;
605
606   HELP ("IRIX \"hinv -c processor\" output");
607
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)
611     {
612       while (fgets (buf, sizeof (buf), fp) != NULL)
613         {
614           end = 0;
615           if (sscanf (buf, "Processor 0: %lf MHZ%n", &val, &end) == 1
616               && end != 0)
617             {
618             found:
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);
622               ret = 1;
623               break;
624             }
625           end = 0;
626           if (sscanf (buf, "%d %lf MHZ%n", &nproc, &val, &end) == 2
627               && end != 0)
628             goto found;
629         }
630       pclose (fp);
631     }
632 #endif
633   return ret;
634 }
635
636
637 /* processor_info() for Solaris.  "psrinfo" is the command-line interface to
638    this.  "prtconf -vp" gives similar information.
639
640    Apple Darwin has a processor_info, but in an incompatible style.  It
641    doesn't have <sys/processor.h>, so test for that.  */
642
643 static int
644 freq_processor_info (int help)
645 {
646 #if HAVE_PROCESSOR_INFO && HAVE_SYS_PROCESSOR_H
647   processor_info_t  p;
648   int  i, n, mhz = 0;
649
650   HELP ("processor_info() pi_clock");
651
652   n = sysconf (_SC_NPROCESSORS_CONF);
653   for (i = 0; i < n; i++)
654     {
655       if (processor_info (i, &p) != 0)
656         continue;
657       if (p.pi_state != P_ONLINE)
658         continue;
659
660       if (mhz != 0 && p.pi_clock != mhz)
661         {
662           fprintf (stderr,
663                    "freq_processor_info(): There's more than one CPU and they have different clock speeds\n");
664           return 0;
665         }
666
667       mhz = p.pi_clock;
668     }
669
670   speed_cycletime = 1.0e-6 / (double) mhz;
671
672   if (speed_option_verbose)
673     printf ("Using processor_info() %d mhz for cycle time %.3g\n",
674             mhz, speed_cycletime);
675   return 1;
676
677 #else
678   return 0;
679 #endif
680 }
681
682
683 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY
684 static double
685 freq_measure_gettimeofday_one (void)
686 {
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);
693 }
694 #endif
695
696 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE
697 static double
698 freq_measure_getrusage_one (void)
699 {
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);
706 }
707 #endif
708
709
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
715
716 double
717 freq_measure (const char *name, double (*one) (void))
718 {
719   double  t[MEASURE_MAX_ATTEMPTS];
720   int     i, j;
721
722   for (i = 0; i < numberof (t); i++)
723     {
724       t[i] = (*one) ();
725
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]);
730
731       for (j = 0; j+MEASURE_MATCH-1 <= i; j++)
732         {
733           if (t[j+MEASURE_MATCH-1] <= t[j] * MEASURE_TOLERANCE)
734             {
735               /* use the average of the range found */
736                 return (t[j+MEASURE_MATCH-1] + t[j]) / 2.0;
737             }
738         }
739     }
740   return -1.0;
741 }
742
743 static int
744 freq_measure_getrusage (int help)
745 {
746 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETRUSAGE
747   double  cycletime;
748
749   if (! getrusage_microseconds_p ())
750     return 0;
751   if (! cycles_works_p ())
752     return 0;
753
754   HELP ("cycle counter measured with microsecond getrusage()");
755
756   cycletime = freq_measure ("getrusage", freq_measure_getrusage_one);
757   if (cycletime == -1.0)
758     return 0;
759
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);
764   return 1;
765
766 #else
767   return 0;
768 #endif
769 }
770
771 static int
772 freq_measure_gettimeofday (int help)
773 {
774 #if HAVE_SPEED_CYCLECOUNTER && HAVE_GETTIMEOFDAY
775   double  cycletime;
776
777   if (! gettimeofday_microseconds_p ())
778     return 0;
779   if (! cycles_works_p ())
780     return 0;
781
782   HELP ("cycle counter measured with microsecond gettimeofday()");
783
784   cycletime = freq_measure ("gettimeofday", freq_measure_gettimeofday_one);
785   if (cycletime == -1.0)
786     return 0;
787
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);
792   return 1;
793 #else
794   return 0;
795 #endif
796 }
797
798
799 /* Each function returns 1 if it succeeds in setting speed_cycletime, or 0
800    if not.
801
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
805    wasteful of cpu.  */
806
807 static int
808 freq_all (int help)
809 {
810   return
811     /* This should be first, so an environment variable can override
812        anything the system gives. */
813     freq_environment (help)
814
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)
822
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)
826
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);
834 }
835
836
837 void
838 speed_cycletime_init (void)
839 {
840   static int  attempted = 0;
841
842   if (attempted)
843     return;
844   attempted = 1;
845
846   if (freq_all (0))
847     return;
848
849   if (speed_option_verbose)
850     printf ("CPU frequency couldn't be determined\n");
851 }
852
853
854 void
855 speed_cycletime_fail (const char *str)
856 {
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");
860   freq_all (1);
861   abort ();
862 }
863
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.  */
868 void
869 speed_cycletime_need_cycles (void)
870 {
871   speed_time_init ();
872   if (speed_cycletime == 0.0)
873     speed_cycletime_fail
874       ("Need to know CPU frequency to give times in cycles");
875 }
876 void
877 speed_cycletime_need_seconds (void)
878 {
879   speed_time_init ();
880   if (speed_cycletime == 1.0)
881     speed_cycletime_fail
882       ("Need to know CPU frequency to convert cycles to seconds");
883 }