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