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