comparison src/getloadavg.c @ 428:3ecd8885ac67 r21-2-22

Import from CVS: tag r21-2-22
author cvs
date Mon, 13 Aug 2007 11:28:15 +0200
parents
children 8de8e3f6228a
comparison
equal deleted inserted replaced
427:0a0253eac470 428:3ecd8885ac67
1 /* Get the system load averages.
2 Copyright (C) 1985, 86, 87, 88, 89, 91, 92, 93, 1994, 1995
3 Free Software Foundation, Inc.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 /* Compile-time symbols that this file uses:
23
24 FIXUP_KERNEL_SYMBOL_ADDR() Adjust address in returned struct nlist.
25 KERNEL_FILE Pathname of the kernel to nlist.
26 LDAV_CVT() Scale the load average from the kernel.
27 Returns a double.
28 LDAV_SYMBOL Name of kernel symbol giving load average.
29 LOAD_AVE_TYPE Type of the load average array in the kernel.
30 Must be defined unless one of
31 apollo, DGUX, NeXT, or UMAX is defined;
32 otherwise, no load average is available.
33 NLIST_STRUCT Include nlist.h, not a.out.h, and
34 the nlist n_name element is a pointer,
35 not an array.
36 NLIST_NAME_UNION struct nlist has an n_un member, not n_name.
37 LINUX_LDAV_FILE [__linux__]: File containing load averages.
38
39 Specific system predefines this file uses, aside from setting
40 default values if not emacs:
41
42 apollo
43 BSD Real BSD, not just BSD-like.
44 convex
45 DGUX
46 hpux
47 MSDOS No-op for MSDOS.
48 NeXT
49 sgi
50 sequent Sequent Dynix 3.x.x (BSD)
51 _SEQUENT_ Sequent DYNIX/ptx 1.x.x (SYSV)
52 sony_news NEWS-OS (works at least for 4.1C)
53 UMAX
54 UMAX4_3
55 WIN32 No-op for Windows95/NT.
56 __linux__ Linux: assumes /proc filesystem mounted.
57 Support from Michael K. Johnson.
58 __NetBSD__ NetBSD: assumes /kern filesystem mounted.
59 __OpenBSD__ OpenBSD: ditto.
60
61 In addition, to avoid nesting many #ifdefs, we internally set
62 LDAV_DONE to indicate that the load average has been computed.
63
64 We also #define LDAV_PRIVILEGED if a program will require
65 special installation to be able to call getloadavg. */
66
67 /* This should always be first. */
68 #ifdef HAVE_CONFIG_H
69 #include <config.h>
70 #endif
71
72 #ifndef WINDOWSNT
73 #ifndef __CYGWIN32__
74
75 #include <sys/types.h>
76
77 /* Both the Emacs and non-Emacs sections want this. Some
78 configuration files' definitions for the LOAD_AVE_CVT macro (like
79 sparc.h's) use macros like FSCALE, defined here. */
80 #ifdef unix
81 #include <sys/param.h>
82 #endif
83
84 #ifdef XEMACS
85 #include "lisp.h"
86 #include "sysfile.h" /* for encapsulated open, close, read, write */
87 #endif /* XEMACS */
88
89 /* Exclude all the code except the test program at the end
90 if the system has its own `getloadavg' function.
91
92 The declaration of `errno' is needed by the test program
93 as well as the function itself, so it comes first. */
94
95 #include <errno.h>
96
97 #ifndef HAVE_GETLOADAVG
98
99 /* The existing Emacs configuration files define a macro called
100 LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and
101 returns the load average multiplied by 100. What we actually want
102 is a macro called LDAV_CVT, which returns the load average as an
103 unmultiplied double.
104
105 For backwards compatibility, we'll define LDAV_CVT in terms of
106 LOAD_AVE_CVT, but future machine config files should just define
107 LDAV_CVT directly. */
108
109 #if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT)
110 #define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
111 #endif
112
113 #ifdef XEMACS
114 #if defined (HAVE_KSTAT_H)
115 #include <kstat.h>
116 #endif /* HAVE_KSTAT_H */
117 #endif /* XEMACS */
118
119 #if !defined (BSD) && defined (ultrix)
120 /* Ultrix behaves like BSD on Vaxen. */
121 #define BSD
122 #endif
123
124 #ifdef NeXT
125 /* NeXT in the 2.{0,1,2} releases defines BSD in <sys/param.h>, which
126 conflicts with the definition understood in this file, that this
127 really is BSD. */
128 #undef BSD
129
130 /* NeXT defines FSCALE in <sys/param.h>. However, we take FSCALE being
131 defined to mean that the nlist method should be used, which is not true. */
132 #undef FSCALE
133 #endif
134
135 /* Set values that are different from the defaults, which are
136 set a little farther down with #ifndef. */
137
138
139 /* Some shorthands. */
140
141 #if defined (HPUX) && !defined (hpux)
142 #define hpux
143 #endif
144
145 #if defined(hp300) && !defined(hpux)
146 #define MORE_BSD
147 #endif
148
149 #if defined(ultrix) && defined(mips)
150 #define decstation
151 #endif
152
153 #if (defined(sun) && defined(SVR4)) || defined (SOLARIS2)
154 #define SUNOS_5
155 #endif
156
157 #if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
158 #define OSF_ALPHA
159 #include <netdb.h>
160 #include <netinet/in.h> /* Needed for Digital UNIX V3 */
161 #include <net/proto_net.h>
162 #include <sys/table.h>
163 #endif
164
165 #if defined (__osf__) && (defined (mips) || defined (__mips__))
166 #define OSF_MIPS
167 #include <sys/table.h>
168 #endif
169
170 /* UTek's /bin/cc on the 4300 has no architecture specific cpp define by
171 default, but _MACH_IND_SYS_TYPES is defined in <sys/types.h>. Combine
172 that with a couple of other things and we'll have a unique match. */
173 #if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES)
174 #define tek4300 /* Define by emacs, but not by other users. */
175 #endif
176
177
178 /* VAX C can't handle multi-line #ifs, or lines longer than 256 chars. */
179 #ifndef LOAD_AVE_TYPE
180
181 #ifdef MORE_BSD
182 #define LOAD_AVE_TYPE long
183 #endif
184
185 #ifdef sun
186 #define LOAD_AVE_TYPE long
187 #endif
188
189 #ifdef decstation
190 #define LOAD_AVE_TYPE long
191 #endif
192
193 #ifdef _SEQUENT_
194 #define LOAD_AVE_TYPE long
195 #endif
196
197 #ifdef sgi
198 #define LOAD_AVE_TYPE long
199 #endif
200
201 #ifdef SVR4
202 #define LOAD_AVE_TYPE long
203 #endif
204
205 #ifdef sony_news
206 #define LOAD_AVE_TYPE long
207 #endif
208
209 #ifdef sequent
210 #define LOAD_AVE_TYPE long
211 #endif
212
213 #ifdef OSF_ALPHA
214 #define LOAD_AVE_TYPE long
215 #endif
216
217 #if defined (ardent) && defined (titan)
218 #define LOAD_AVE_TYPE long
219 #endif
220
221 #ifdef tek4300
222 #define LOAD_AVE_TYPE long
223 #endif
224
225 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
226 #define LOAD_AVE_TYPE long
227 #endif
228
229 #ifdef _AIX
230 #define LOAD_AVE_TYPE long
231 #endif
232
233 #ifdef convex
234 #define LOAD_AVE_TYPE double
235 #ifndef LDAV_CVT
236 #define LDAV_CVT(n) (n)
237 #endif
238 #endif
239
240 #endif /* No LOAD_AVE_TYPE. */
241
242 #ifdef OSF_ALPHA
243 /* <sys/param.h> defines an incorrect value for FSCALE on Alpha OSF/1,
244 according to ghazi@noc.rutgers.edu. */
245 #undef FSCALE
246 #define FSCALE 1024.0
247 #endif
248
249 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
250 /* <sys/param.h> defines an incorrect value for FSCALE on an
251 Alliant FX/2800 Concentrix 2.2, according to ghazi@noc.rutgers.edu. */
252 #undef FSCALE
253 #define FSCALE 100.0
254 #endif
255
256
257 #ifndef FSCALE
258
259 /* SunOS and some others define FSCALE in sys/param.h. */
260
261 #ifdef MORE_BSD
262 #define FSCALE 2048.0
263 #endif
264
265 #if defined(MIPS) || defined(SVR4) || defined(decstation)
266 #define FSCALE 256
267 #endif
268
269 #if defined (sgi) || defined (sequent)
270 /* Sometimes both MIPS and sgi are defined, so FSCALE was just defined
271 above under #ifdef MIPS. But we want the sgi value. */
272 #undef FSCALE
273 #define FSCALE 1000.0
274 #endif
275
276 #if defined (ardent) && defined (titan)
277 #define FSCALE 65536.0
278 #endif
279
280 #ifdef tek4300
281 #define FSCALE 100.0
282 #endif
283
284 #ifdef _AIX
285 #define FSCALE 65536.0
286 #endif
287
288 #endif /* Not FSCALE. */
289
290 #if !defined (LDAV_CVT) && defined (FSCALE)
291 #define LDAV_CVT(n) (((double) (n)) / FSCALE)
292 #endif
293
294 /* VAX C can't handle multi-line #ifs, or lines longer that 256 characters. */
295 #ifndef NLIST_STRUCT
296
297 #ifdef MORE_BSD
298 #define NLIST_STRUCT
299 #endif
300
301 #ifdef sun
302 #define NLIST_STRUCT
303 #endif
304
305 #ifdef decstation
306 #define NLIST_STRUCT
307 #endif
308
309 #ifdef hpux
310 #define NLIST_STRUCT
311 #endif
312
313 #if defined (_SEQUENT_) || defined (sequent)
314 #define NLIST_STRUCT
315 #endif
316
317 #ifdef sgi
318 #define NLIST_STRUCT
319 #endif
320
321 #ifdef SVR4
322 #define NLIST_STRUCT
323 #endif
324
325 #ifdef sony_news
326 #define NLIST_STRUCT
327 #endif
328
329 #ifdef OSF_ALPHA
330 #define NLIST_STRUCT
331 #endif
332
333 #if defined (ardent) && defined (titan)
334 #define NLIST_STRUCT
335 #endif
336
337 #ifdef tek4300
338 #define NLIST_STRUCT
339 #endif
340
341 #ifdef butterfly
342 #define NLIST_STRUCT
343 #endif
344
345 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
346 #define NLIST_STRUCT
347 #endif
348
349 #ifdef _AIX
350 #define NLIST_STRUCT
351 #endif
352
353 #endif /* defined (NLIST_STRUCT) */
354
355
356 #if defined(sgi) || (defined(mips) && !defined(BSD))
357 #define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
358 #endif
359
360
361 #if !defined (KERNEL_FILE) && defined (sequent)
362 #define KERNEL_FILE "/dynix"
363 #endif
364
365 #if !defined (KERNEL_FILE) && defined (hpux)
366 #define KERNEL_FILE "/hp-ux"
367 #endif
368
369 #if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || defined(SVR4) || (defined (ardent) && defined (titan)))
370 #define KERNEL_FILE "/unix"
371 #endif
372
373
374 #if !defined (LDAV_SYMBOL) && defined (alliant)
375 #define LDAV_SYMBOL "_Loadavg"
376 #endif
377
378 #if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
379 #define LDAV_SYMBOL "avenrun"
380 #endif
381
382 #ifdef HAVE_UNISTD_H
383 #include <unistd.h>
384 #endif
385
386 #include <stdio.h>
387
388 /* LOAD_AVE_TYPE should only get defined if we're going to use the
389 nlist method. */
390 #if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL))
391 #define LOAD_AVE_TYPE double
392 #endif
393
394 #ifdef LOAD_AVE_TYPE
395
396 #ifndef NLIST_STRUCT
397 #include <a.out.h>
398 #else /* NLIST_STRUCT */
399 #include <nlist.h>
400 #endif /* NLIST_STRUCT */
401
402 #ifdef SUNOS_5
403 #include <fcntl.h>
404 #include <kvm.h>
405 #endif
406
407 #ifndef KERNEL_FILE
408 #define KERNEL_FILE "/vmunix"
409 #endif /* KERNEL_FILE */
410
411 #ifndef LDAV_SYMBOL
412 #define LDAV_SYMBOL "_avenrun"
413 #endif /* LDAV_SYMBOL */
414
415 #ifndef LDAV_CVT
416 #define LDAV_CVT(n) ((double) (n))
417 #endif /* !LDAV_CVT */
418
419 #endif /* LOAD_AVE_TYPE */
420
421 #ifdef NeXT
422 #ifdef HAVE_MACH_MACH_H
423 #include <mach/mach.h>
424 #else
425 #include <mach.h>
426 #endif
427 #endif /* NeXT */
428
429 #ifdef sgi
430 #include <sys/sysmp.h>
431 #endif /* sgi */
432
433 #ifdef UMAX
434 #include <stdio.h>
435 #include <signal.h>
436 #include <sys/time.h>
437 #include <sys/wait.h>
438 #include <sys/syscall.h>
439
440 #ifdef UMAX_43
441 #include <machine/cpu.h>
442 #include <inq_stats/statistics.h>
443 #include <inq_stats/sysstats.h>
444 #include <inq_stats/cpustats.h>
445 #include <inq_stats/procstats.h>
446 #else /* Not UMAX_43. */
447 #include <sys/sysdefs.h>
448 #include <sys/statistics.h>
449 #include <sys/sysstats.h>
450 #include <sys/cpudefs.h>
451 #include <sys/cpustats.h>
452 #include <sys/procstats.h>
453 #endif /* Not UMAX_43. */
454 #endif /* UMAX */
455
456 #ifdef DGUX
457 #include <sys/dg_sys_info.h>
458 #endif
459
460 #ifdef XEMACS
461 #if defined (HAVE_SYS_PSTAT_H)
462 #include <sys/pstat.h>
463 #endif /* HAVE_SYS_PSTAT_H (on HPUX) */
464 #endif /* XEMACS */
465
466 #if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
467 #include <fcntl.h>
468 #else
469 #include <sys/file.h>
470 #endif
471
472 /* Avoid static vars inside a function since in HPUX they dump as pure. */
473
474 #ifdef NeXT
475 static processor_set_t default_set;
476 static int getloadavg_initialized;
477 #endif /* NeXT */
478
479 #ifdef UMAX
480 static unsigned int cpus = 0;
481 static unsigned int samples;
482 #endif /* UMAX */
483
484 #ifdef DGUX
485 static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */
486 #endif /* DGUX */
487
488 #ifdef LOAD_AVE_TYPE
489 /* File descriptor open to /dev/kmem */
490 static int channel;
491 /* Nonzero iff channel is valid. */
492 static int getloadavg_initialized;
493 /* Offset in kmem to seek to read load average, or 0 means invalid. */
494 static long offset;
495
496 #ifndef sgi
497 static struct nlist nl[2];
498 #endif /* not sgi */
499
500 #ifdef SUNOS_5
501 static kvm_t *kd;
502 #endif /* SUNOS_5 */
503
504 #ifndef countof
505 # define countof(x) (sizeof (x) / sizeof (*(x)))
506 #endif
507
508 #endif /* LOAD_AVE_TYPE */
509
510 /* Put the 1 minute, 5 minute and 15 minute load averages
511 into the first NELEM elements of LOADAVG.
512 Return the number written (never more than 3, but may be less than NELEM),
513 or -1 if an error occurred. */
514
515 int
516 getloadavg (double loadavg[], int nelem)
517 {
518 int elem = 0; /* Return value. */
519
520 #ifdef NO_GET_LOAD_AVG
521 #define LDAV_DONE
522 /* Set errno to zero to indicate that there was no particular error;
523 this function just can't work at all on this system. */
524 errno = 0;
525 elem = -2;
526 #endif /* NO_GET_LOAD_AVG */
527
528 #if ! defined (LDAV_DONE) && defined (HAVE_KSTAT_H) && defined (HAVE_LIBKSTAT)
529 #define LDAV_DONE
530 /* getloadavg is best implemented using kstat (kernel stats), on
531 systems (like SunOS5) that support it, since you don't need special
532 privileges to use it.
533
534 Initial implementation courtesy Zlatko Calusic <zcalusic@carnet.hr>.
535 Integrated to XEmacs by Hrvoje Niksic <hniksic@xemacs.org>.
536 Additional cleanup by Hrvoje Niksic, based on code published by
537 Casper Dik <Casper.Dik@Holland.Sun.Com>. */
538 kstat_ctl_t *kc;
539 kstat_t *ksp;
540 static char *avestrings[] = { "avenrun_1min",
541 "avenrun_5min",
542 "avenrun_15min" };
543
544 if (nelem > countof (avestrings))
545 nelem = countof (avestrings);
546
547 kc = kstat_open ();
548 if (!kc)
549 return -1;
550 ksp = kstat_lookup (kc, "unix", 0, "system_misc");
551 if (!ksp)
552 {
553 kstat_close (kc);
554 return -1;
555 }
556 if (kstat_read (kc, ksp, 0) < 0)
557 {
558 kstat_close (kc);
559 return -1;
560 }
561 for (elem = 0; elem < nelem; elem++)
562 {
563 kstat_named_t *kn =
564 (kstat_named_t *) kstat_data_lookup (ksp, avestrings[elem]);
565 if (!kn)
566 {
567 kstat_close (kc);
568 return -1;
569 }
570 loadavg[elem] = (double)kn->value.ul / FSCALE;
571 }
572 kstat_close (kc);
573 #endif /* HAVE_KSTAT_H && HAVE_LIBKSTAT */
574
575 #if !defined (LDAV_DONE) && defined (HAVE_SYS_PSTAT_H)
576 #define LDAV_DONE
577 /* This is totally undocumented, and is not guaranteed to work, but
578 mayhap it might .... If it does work, it will work only on HP-UX
579 8.0 or later. -- Darryl Okahata <darrylo@sr.hp.com> */
580 #undef LOAD_AVE_TYPE /* Make sure these don't exist. */
581 #undef LOAD_AVE_CVT
582 #undef LDAV_SYMBOL
583 struct pst_dynamic procinfo;
584 union pstun statbuf;
585
586 statbuf.pst_dynamic = &procinfo;
587 if (pstat (PSTAT_DYNAMIC, statbuf, sizeof (struct pst_dynamic), 0, 0) == -1)
588 return (-1);
589 loadavg[elem++] = procinfo.psd_avg_1_min;
590 loadavg[elem++] = procinfo.psd_avg_5_min;
591 loadavg[elem++] = procinfo.psd_avg_15_min;
592 #endif /* HPUX */
593
594 #if !defined (LDAV_DONE) && defined (__linux__)
595 #define LDAV_DONE
596 #undef LOAD_AVE_TYPE
597
598 #ifndef LINUX_LDAV_FILE
599 #define LINUX_LDAV_FILE "/proc/loadavg"
600 #endif
601
602 char ldavgbuf[40];
603 double load_ave[3];
604 int fd, count;
605
606 fd = open (LINUX_LDAV_FILE, O_RDONLY);
607 if (fd == -1)
608 return -1;
609 count = read (fd, ldavgbuf, 40);
610 (void) close (fd);
611 if (count <= 0)
612 return -1;
613
614 count = sscanf (ldavgbuf, "%lf %lf %lf",
615 &load_ave[0], &load_ave[1], &load_ave[2]);
616 if (count < 1)
617 return -1;
618
619 for (elem = 0; elem < nelem && elem < count; elem++)
620 loadavg[elem] = load_ave[elem];
621 #endif /* __linux__ */
622
623 #if !defined (LDAV_DONE) && defined (__NetBSD__) || defined (__OpenBSD__)
624 #define LDAV_DONE
625 #undef LOAD_AVE_TYPE
626
627 #ifndef NETBSD_LDAV_FILE
628 #define NETBSD_LDAV_FILE "/kern/loadavg"
629 #endif
630
631 unsigned long int load_ave[3], scale;
632 int count;
633 FILE *fp;
634
635 fp = fopen (NETBSD_LDAV_FILE, "r");
636 if (fp == NULL)
637 return -1;
638 count = fscanf (fp, "%lu %lu %lu %lu\n",
639 &load_ave[0], &load_ave[1], &load_ave[2],
640 &scale);
641 (void) fclose (fp);
642 if (count != 4)
643 return -1;
644
645 for (elem = 0; elem < nelem; elem++)
646 loadavg[elem] = (double) load_ave[elem] / (double) scale;
647 #endif /* __NetBSD__ or __OpenBSD__ */
648
649 #if !defined (LDAV_DONE) && defined (NeXT)
650 #define LDAV_DONE
651 /* The NeXT code was adapted from iscreen 3.2. */
652
653 host_t host;
654 struct processor_set_basic_info info;
655 unsigned info_count;
656
657 /* We only know how to get the 1-minute average for this system,
658 so even if the caller asks for more than 1, we only return 1. */
659
660 if (!getloadavg_initialized)
661 {
662 if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
663 getloadavg_initialized = 1;
664 }
665
666 if (getloadavg_initialized)
667 {
668 info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
669 if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
670 (processor_set_info_t) &info, &info_count)
671 != KERN_SUCCESS)
672 getloadavg_initialized = 0;
673 else
674 {
675 if (nelem > 0)
676 loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
677 }
678 }
679
680 if (!getloadavg_initialized)
681 return -1;
682 #endif /* NeXT */
683
684 #if !defined (LDAV_DONE) && defined (UMAX)
685 #define LDAV_DONE
686 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
687 have a /dev/kmem. Information about the workings of the running kernel
688 can be gathered with inq_stats system calls.
689 We only know how to get the 1-minute average for this system. */
690
691 struct proc_summary proc_sum_data;
692 struct stat_descr proc_info;
693 double load;
694 REGISTER unsigned int i, j;
695
696 if (cpus == 0)
697 {
698 REGISTER unsigned int c, i;
699 struct cpu_config conf;
700 struct stat_descr desc;
701
702 desc.sd_next = 0;
703 desc.sd_subsys = SUBSYS_CPU;
704 desc.sd_type = CPUTYPE_CONFIG;
705 desc.sd_addr = (char *) &conf;
706 desc.sd_size = sizeof conf;
707
708 if (inq_stats (1, &desc))
709 return -1;
710
711 c = 0;
712 for (i = 0; i < conf.config_maxclass; ++i)
713 {
714 struct class_stats stats;
715 memset ((char *) &stats, 0, sizeof stats);
716
717 desc.sd_type = CPUTYPE_CLASS;
718 desc.sd_objid = i;
719 desc.sd_addr = (char *) &stats;
720 desc.sd_size = sizeof stats;
721
722 if (inq_stats (1, &desc))
723 return -1;
724
725 c += stats.class_numcpus;
726 }
727 cpus = c;
728 samples = cpus < 2 ? 3 : (2 * cpus / 3);
729 }
730
731 proc_info.sd_next = 0;
732 proc_info.sd_subsys = SUBSYS_PROC;
733 proc_info.sd_type = PROCTYPE_SUMMARY;
734 proc_info.sd_addr = (char *) &proc_sum_data;
735 proc_info.sd_size = sizeof (struct proc_summary);
736 proc_info.sd_sizeused = 0;
737
738 if (inq_stats (1, &proc_info) != 0)
739 return -1;
740
741 load = proc_sum_data.ps_nrunnable;
742 j = 0;
743 for (i = samples - 1; i > 0; --i)
744 {
745 load += proc_sum_data.ps_nrun[j];
746 if (j++ == PS_NRUNSIZE)
747 j = 0;
748 }
749
750 if (nelem > 0)
751 loadavg[elem++] = load / samples / cpus;
752 #endif /* UMAX */
753
754 #if !defined (LDAV_DONE) && defined (DGUX)
755 #define LDAV_DONE
756 /* This call can return -1 for an error, but with good args
757 it's not supposed to fail. The first argument is for no
758 apparent reason of type `long int *'. */
759 dg_sys_info ((long int *) &load_info,
760 DG_SYS_INFO_LOAD_INFO_TYPE,
761 DG_SYS_INFO_LOAD_VERSION_0);
762
763 if (nelem > 0)
764 loadavg[elem++] = load_info.one_minute;
765 if (nelem > 1)
766 loadavg[elem++] = load_info.five_minute;
767 if (nelem > 2)
768 loadavg[elem++] = load_info.fifteen_minute;
769 #endif /* DGUX */
770
771 #if !defined (LDAV_DONE) && defined (apollo)
772 #define LDAV_DONE
773 /* Apollo code from lisch@mentorg.com (Ray Lischner).
774
775 This system call is not documented. The load average is obtained as
776 three long integers, for the load average over the past minute,
777 five minutes, and fifteen minutes. Each value is a scaled integer,
778 with 16 bits of integer part and 16 bits of fraction part.
779
780 I'm not sure which operating system first supported this system call,
781 but I know that SR10.2 supports it. */
782
783 extern void proc1_$get_loadav ();
784 unsigned long load_ave[3];
785
786 proc1_$get_loadav (load_ave);
787
788 if (nelem > 0)
789 loadavg[elem++] = load_ave[0] / 65536.0;
790 if (nelem > 1)
791 loadavg[elem++] = load_ave[1] / 65536.0;
792 if (nelem > 2)
793 loadavg[elem++] = load_ave[2] / 65536.0;
794 #endif /* apollo */
795
796 #if !defined (LDAV_DONE) && defined (OSF_MIPS)
797 #define LDAV_DONE
798
799 struct tbl_loadavg load_ave;
800 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
801 loadavg[elem++]
802 = (load_ave.tl_lscale == 0
803 ? load_ave.tl_avenrun.d[0]
804 : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
805 #endif /* OSF_MIPS */
806
807 #if !defined (LDAV_DONE) && (defined (MSDOS) || defined (WIN32))
808 #define LDAV_DONE
809
810 /* A faithful emulation is going to have to be saved for a rainy day. */
811 for ( ; elem < nelem; elem++)
812 {
813 loadavg[elem] = 0.0;
814 }
815 #endif /* MSDOS */
816
817 #if !defined (LDAV_DONE) && defined (OSF_ALPHA)
818 #define LDAV_DONE
819
820 struct tbl_loadavg load_ave;
821 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
822 for (elem = 0; elem < nelem; elem++)
823 loadavg[elem]
824 = (load_ave.tl_lscale == 0
825 ? load_ave.tl_avenrun.d[elem]
826 : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
827 #endif /* OSF_ALPHA */
828
829 #if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE)
830
831 /* UNIX-specific code -- read the average from /dev/kmem. */
832
833 #define LDAV_PRIVILEGED /* This code requires special installation. */
834
835 LOAD_AVE_TYPE load_ave[3];
836
837 /* Get the address of LDAV_SYMBOL. */
838 if (offset == 0)
839 {
840 #ifndef sgi
841 #ifndef NLIST_STRUCT
842 strcpy (nl[0].n_name, LDAV_SYMBOL);
843 strcpy (nl[1].n_name, "");
844 #else /* NLIST_STRUCT */
845 #ifdef NLIST_NAME_UNION
846 nl[0].n_un.n_name = LDAV_SYMBOL;
847 nl[1].n_un.n_name = 0;
848 #else /* not NLIST_NAME_UNION */
849 nl[0].n_name = (char *) LDAV_SYMBOL;
850 nl[1].n_name = 0;
851 #endif /* not NLIST_NAME_UNION */
852 #endif /* NLIST_STRUCT */
853
854 #ifndef SUNOS_5
855 if (
856 #if !(defined (_AIX) && !defined (ps2))
857 nlist (KERNEL_FILE, nl)
858 #else /* _AIX */
859 knlist (nl, 1, sizeof (nl[0]))
860 #endif
861 >= 0)
862 /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */
863 {
864 #ifdef FIXUP_KERNEL_SYMBOL_ADDR
865 FIXUP_KERNEL_SYMBOL_ADDR (nl);
866 #endif
867 offset = nl[0].n_value;
868 }
869 #endif /* !SUNOS_5 */
870 #else /* sgi */
871 int ldav_off;
872
873 ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
874 if (ldav_off != -1)
875 offset = (long) ldav_off & 0x7fffffff;
876 #endif /* sgi */
877 }
878
879 /* Make sure we have /dev/kmem open. */
880 if (!getloadavg_initialized)
881 {
882 #ifndef SUNOS_5
883 channel = open ("/dev/kmem", 0);
884 if (channel >= 0)
885 {
886 /* Set the channel to close on exec, so it does not
887 litter any child's descriptor table. */
888 #ifdef FD_SETFD
889 #ifndef FD_CLOEXEC
890 #define FD_CLOEXEC 1
891 #endif
892 (void) fcntl (channel, F_SETFD, FD_CLOEXEC);
893 #endif
894 getloadavg_initialized = 1;
895 }
896 #else /* SUNOS_5 */
897 /* We pass 0 for the kernel, corefile, and swapfile names
898 to use the currently running kernel. */
899 kd = kvm_open (0, 0, 0, O_RDONLY, 0);
900 if (kd != 0)
901 {
902 /* nlist the currently running kernel. */
903 kvm_nlist (kd, nl);
904 offset = nl[0].n_value;
905 getloadavg_initialized = 1;
906 }
907 #endif /* SUNOS_5 */
908 }
909
910 /* If we can, get the load average values. */
911 if (offset && getloadavg_initialized)
912 {
913 /* Try to read the load. */
914 #ifndef SUNOS_5
915 if (lseek (channel, offset, 0) == -1L
916 || read (channel, (char *) load_ave, sizeof (load_ave))
917 != sizeof (load_ave))
918 {
919 close (channel);
920 getloadavg_initialized = 0;
921 }
922 #else /* SUNOS_5 */
923 if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
924 != sizeof (load_ave))
925 {
926 kvm_close (kd);
927 getloadavg_initialized = 0;
928 }
929 #endif /* SUNOS_5 */
930 }
931
932 if (offset == 0 || !getloadavg_initialized)
933 return -1;
934
935 if (nelem > 0)
936 loadavg[elem++] = LDAV_CVT (load_ave[0]);
937 if (nelem > 1)
938 loadavg[elem++] = LDAV_CVT (load_ave[1]);
939 if (nelem > 2)
940 loadavg[elem++] = LDAV_CVT (load_ave[2]);
941
942 #define LDAV_DONE
943 #endif /* !LDAV_DONE && LOAD_AVE_TYPE */
944
945 return elem;
946 }
947
948 #endif /* ! HAVE_GETLOADAVG */
949
950 #ifdef TEST
951 void
952 main (int argc, char **argv)
953 {
954 int naptime = 0;
955
956 if (argc > 1)
957 naptime = atoi (argv[1]);
958
959 while (1)
960 {
961 double avg[3];
962 int loads;
963
964 errno = 0; /* Don't be misled if it doesn't set errno. */
965 loads = getloadavg (avg, 3);
966 if (loads == -1)
967 {
968 perror ("Error getting load average");
969 exit (1);
970 }
971 if (loads > 0)
972 printf ("1-minute: %f ", avg[0]);
973 if (loads > 1)
974 printf ("5-minute: %f ", avg[1]);
975 if (loads > 2)
976 printf ("15-minute: %f ", avg[2]);
977 if (loads > 0)
978 putchar ('\n');
979
980 if (naptime == 0)
981 break;
982 sleep (naptime);
983 }
984
985 exit (0);
986 }
987 #endif /* TEST */
988
989 #else
990
991 /* Emulate getloadavg. */
992 int
993 getloadavg (double loadavg[], int nelem)
994 {
995 int i;
996
997 /* A faithful emulation is going to have to be saved for a rainy day. */
998 for (i = 0; i < nelem; i++)
999 {
1000 loadavg[i] = 0.0;
1001 }
1002 return i;
1003 }
1004
1005 #endif /*__GNUWIN32__*/
1006 #endif /* WINDOWSNT */