1 /* Get the system load averages.
2 Copyright (C) 1985, 86, 87, 88, 89, 91, 92, 93, 1994, 1995
3 Free Software Foundation, Inc.
5 This file is part of XEmacs.
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
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
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. */
22 /* Compile-time symbols that this file uses:
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.
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,
36 NLIST_NAME_UNION struct nlist has an n_un member, not n_name.
37 LINUX_LDAV_FILE [__linux__]: File containing load averages.
39 Specific system predefines this file uses, aside from setting
40 default values if not emacs:
43 BSD Real BSD, not just BSD-like.
47 MSDOS No-op for MSDOS.
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)
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.
61 In addition, to avoid nesting many #ifdefs, we internally set
62 LDAV_DONE to indicate that the load average has been computed.
64 We also #define LDAV_PRIVILEGED if a program will require
65 special installation to be able to call getloadavg. */
67 /* This should always be first. */
75 #include <sys/types.h>
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. */
81 #include <sys/param.h>
86 #include "sysfile.h" /* for encapsulated open, close, read, write */
89 /* Exclude all the code except the test program at the end
90 if the system has its own `getloadavg' function.
92 The declaration of `errno' is needed by the test program
93 as well as the function itself, so it comes first. */
101 #ifndef HAVE_GETLOADAVG
103 /* The existing Emacs configuration files define a macro called
104 LOAD_AVE_CVT, which accepts a value of type LOAD_AVE_TYPE, and
105 returns the load average multiplied by 100. What we actually want
106 is a macro called LDAV_CVT, which returns the load average as an
109 For backwards compatibility, we'll define LDAV_CVT in terms of
110 LOAD_AVE_CVT, but future machine config files should just define
111 LDAV_CVT directly. */
113 #if !defined(LDAV_CVT) && defined(LOAD_AVE_CVT)
114 #define LDAV_CVT(n) (LOAD_AVE_CVT (n) / 100.0)
118 #if defined (HAVE_KSTAT_H)
120 #endif /* HAVE_KSTAT_H */
123 #if !defined (BSD) && defined (ultrix)
124 /* Ultrix behaves like BSD on Vaxen. */
129 /* NeXT in the 2.{0,1,2} releases defines BSD in <sys/param.h>, which
130 conflicts with the definition understood in this file, that this
134 /* NeXT defines FSCALE in <sys/param.h>. However, we take FSCALE being
135 defined to mean that the nlist method should be used, which is not true. */
139 /* Set values that are different from the defaults, which are
140 set a little farther down with #ifndef. */
143 /* Some shorthands. */
145 #if defined (HPUX) && !defined (hpux)
149 #if defined(hp300) && !defined(hpux)
153 #if defined(ultrix) && defined(mips)
157 #if (defined(sun) && defined(SVR4)) || defined (SOLARIS2)
161 #if defined (__osf__) && (defined (__alpha) || defined (__alpha__))
164 #include <netinet/in.h> /* Needed for Digital UNIX V3 */
165 #include <net/proto_net.h>
166 #include <sys/table.h>
169 #if defined (__osf__) && (defined (mips) || defined (__mips__))
171 #include <sys/table.h>
174 /* UTek's /bin/cc on the 4300 has no architecture specific cpp define by
175 default, but _MACH_IND_SYS_TYPES is defined in <sys/types.h>. Combine
176 that with a couple of other things and we'll have a unique match. */
177 #if !defined (tek4300) && defined (unix) && defined (m68k) && defined (mc68000) && defined (mc68020) && defined (_MACH_IND_SYS_TYPES)
178 #define tek4300 /* Define by emacs, but not by other users. */
182 /* VAX C can't handle multi-line #ifs, or lines longer than 256 chars. */
183 #ifndef LOAD_AVE_TYPE
186 #define LOAD_AVE_TYPE long
190 #define LOAD_AVE_TYPE long
194 #define LOAD_AVE_TYPE long
198 #define LOAD_AVE_TYPE long
202 #define LOAD_AVE_TYPE long
206 #define LOAD_AVE_TYPE long
210 #define LOAD_AVE_TYPE long
214 #define LOAD_AVE_TYPE long
218 #define LOAD_AVE_TYPE long
221 #if defined (ardent) && defined (titan)
222 #define LOAD_AVE_TYPE long
226 #define LOAD_AVE_TYPE long
229 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
230 #define LOAD_AVE_TYPE long
234 #define LOAD_AVE_TYPE long
238 #define LOAD_AVE_TYPE double
240 #define LDAV_CVT(n) (n)
244 #endif /* No LOAD_AVE_TYPE. */
247 /* <sys/param.h> defines an incorrect value for FSCALE on Alpha OSF/1,
248 according to ghazi@noc.rutgers.edu. */
250 #define FSCALE 1024.0
253 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
254 /* <sys/param.h> defines an incorrect value for FSCALE on an
255 Alliant FX/2800 Concentrix 2.2, according to ghazi@noc.rutgers.edu. */
263 /* SunOS and some others define FSCALE in sys/param.h. */
266 #define FSCALE 2048.0
269 #if defined(MIPS) || defined(SVR4) || defined(decstation)
273 #if defined (sgi) || defined (sequent)
274 /* Sometimes both MIPS and sgi are defined, so FSCALE was just defined
275 above under #ifdef MIPS. But we want the sgi value. */
277 #define FSCALE 1000.0
280 #if defined (ardent) && defined (titan)
281 #define FSCALE 65536.0
289 #define FSCALE 65536.0
292 #endif /* Not FSCALE. */
294 #if !defined (LDAV_CVT) && defined (FSCALE)
295 #define LDAV_CVT(n) (((double) (n)) / FSCALE)
298 /* VAX C can't handle multi-line #ifs, or lines longer that 256 characters. */
317 #if defined (_SEQUENT_) || defined (sequent)
337 #if defined (ardent) && defined (titan)
349 #if defined(alliant) && defined(i860) /* Alliant FX/2800 */
357 #endif /* defined (NLIST_STRUCT) */
360 #if defined(sgi) || (defined(mips) && !defined(BSD))
361 #define FIXUP_KERNEL_SYMBOL_ADDR(nl) ((nl)[0].n_value &= ~(1 << 31))
365 #if !defined (KERNEL_FILE) && defined (sequent)
366 #define KERNEL_FILE "/dynix"
369 #if !defined (KERNEL_FILE) && defined (hpux)
370 #define KERNEL_FILE "/hp-ux"
373 #if !defined(KERNEL_FILE) && (defined(_SEQUENT_) || defined(MIPS) || defined(SVR4) || defined(ISC) || defined (sgi) || defined(SVR4) || (defined (ardent) && defined (titan)))
374 #define KERNEL_FILE "/unix"
378 #if !defined (LDAV_SYMBOL) && defined (alliant)
379 #define LDAV_SYMBOL "_Loadavg"
382 #if !defined(LDAV_SYMBOL) && ((defined(hpux) && !defined(hp9000s300)) || defined(_SEQUENT_) || defined(SVR4) || defined(ISC) || defined(sgi) || (defined (ardent) && defined (titan)) || defined (_AIX))
383 #define LDAV_SYMBOL "avenrun"
392 /* LOAD_AVE_TYPE should only get defined if we're going to use the
394 #if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL))
395 #define LOAD_AVE_TYPE double
402 #else /* NLIST_STRUCT */
404 #endif /* NLIST_STRUCT */
412 #define KERNEL_FILE "/vmunix"
413 #endif /* KERNEL_FILE */
416 #define LDAV_SYMBOL "_avenrun"
417 #endif /* LDAV_SYMBOL */
420 #define LDAV_CVT(n) ((double) (n))
421 #endif /* !LDAV_CVT */
423 #endif /* LOAD_AVE_TYPE */
426 #ifdef HAVE_MACH_MACH_H
427 #include <mach/mach.h>
434 #include <sys/sysmp.h>
440 #include <sys/time.h>
441 #include <sys/wait.h>
442 #include <sys/syscall.h>
445 #include <machine/cpu.h>
446 #include <inq_stats/statistics.h>
447 #include <inq_stats/sysstats.h>
448 #include <inq_stats/cpustats.h>
449 #include <inq_stats/procstats.h>
450 #else /* Not UMAX_43. */
451 #include <sys/sysdefs.h>
452 #include <sys/statistics.h>
453 #include <sys/sysstats.h>
454 #include <sys/cpudefs.h>
455 #include <sys/cpustats.h>
456 #include <sys/procstats.h>
457 #endif /* Not UMAX_43. */
461 #include <sys/dg_sys_info.h>
465 #if defined (HAVE_SYS_PSTAT_H)
466 #include <sys/pstat.h>
467 #endif /* HAVE_SYS_PSTAT_H (on HPUX) */
470 #if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION)
473 #include <sys/file.h>
476 /* Avoid static vars inside a function since in HPUX they dump as pure. */
479 static processor_set_t default_set;
480 static int getloadavg_initialized;
484 static unsigned int cpus = 0;
485 static unsigned int samples;
489 static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */
493 /* File descriptor open to /dev/kmem */
495 /* Nonzero iff channel is valid. */
496 static int getloadavg_initialized;
497 /* Offset in kmem to seek to read load average, or 0 means invalid. */
501 static struct nlist nl[2];
509 # define countof(x) (sizeof (x) / sizeof (*(x)))
512 #endif /* LOAD_AVE_TYPE */
514 /* Put the 1 minute, 5 minute and 15 minute load averages
515 into the first NELEM elements of LOADAVG.
516 Return the number written (never more than 3, but may be less than NELEM),
517 or -1 if an error occurred. */
520 getloadavg (double loadavg[], int nelem)
522 int elem = 0; /* Return value. */
524 #ifdef NO_GET_LOAD_AVG
526 /* Set errno to zero to indicate that there was no particular error;
527 this function just can't work at all on this system. */
530 #endif /* NO_GET_LOAD_AVG */
532 #if ! defined (LDAV_DONE) && defined (HAVE_KSTAT_H) && defined (HAVE_LIBKSTAT)
534 /* getloadavg is best implemented using kstat (kernel stats), on
535 systems (like SunOS5) that support it, since you don't need special
536 privileges to use it.
538 Initial implementation courtesy Zlatko Calusic <zcalusic@carnet.hr>.
539 Integrated to XEmacs by Hrvoje Niksic <hniksic@srce.hr>.
540 Additional cleanup by Hrvoje Niksic, based on code published by
541 Casper Dik <Casper.Dik@Holland.Sun.Com>. */
544 static char *avestrings[] = { "avenrun_1min",
548 if (nelem > countof (avestrings))
549 nelem = countof (avestrings);
554 ksp = kstat_lookup (kc, "unix", 0, "system_misc");
560 if (kstat_read (kc, ksp, 0) < 0)
565 for (elem = 0; elem < nelem; elem++)
568 (kstat_named_t *) kstat_data_lookup (ksp, avestrings[elem]);
574 loadavg[elem] = (double)kn->value.ul / FSCALE;
577 #endif /* HAVE_KSTAT_H && HAVE_LIBKSTAT */
579 #if !defined (LDAV_DONE) && defined (HAVE_SYS_PSTAT_H)
581 /* This is totally undocumented, and is not guaranteed to work, but
582 mayhap it might .... If it does work, it will work only on HP-UX
583 8.0 or later. -- Darryl Okahata <darrylo@sr.hp.com> */
584 #undef LOAD_AVE_TYPE /* Make sure these don't exist. */
587 struct pst_dynamic procinfo;
590 statbuf.pst_dynamic = &procinfo;
591 if (pstat (PSTAT_DYNAMIC, statbuf, sizeof (struct pst_dynamic), 0, 0) == -1)
593 loadavg[elem++] = procinfo.psd_avg_1_min;
594 loadavg[elem++] = procinfo.psd_avg_5_min;
595 loadavg[elem++] = procinfo.psd_avg_15_min;
598 #if !defined (LDAV_DONE) && defined (__linux__)
602 #ifndef LINUX_LDAV_FILE
603 #define LINUX_LDAV_FILE "/proc/loadavg"
610 fd = open (LINUX_LDAV_FILE, O_RDONLY);
613 count = read (fd, ldavgbuf, 40);
618 count = sscanf (ldavgbuf, "%lf %lf %lf",
619 &load_ave[0], &load_ave[1], &load_ave[2]);
623 for (elem = 0; elem < nelem && elem < count; elem++)
624 loadavg[elem] = load_ave[elem];
625 #endif /* __linux__ */
627 #if !defined (LDAV_DONE) && defined (__NetBSD__) || defined (__OpenBSD__)
631 #ifndef NETBSD_LDAV_FILE
632 #define NETBSD_LDAV_FILE "/kern/loadavg"
635 unsigned long int load_ave[3], scale;
639 fp = fopen (NETBSD_LDAV_FILE, "r");
642 count = fscanf (fp, "%lu %lu %lu %lu\n",
643 &load_ave[0], &load_ave[1], &load_ave[2],
649 for (elem = 0; elem < nelem; elem++)
650 loadavg[elem] = (double) load_ave[elem] / (double) scale;
651 #endif /* __NetBSD__ or __OpenBSD__ */
653 #if !defined (LDAV_DONE) && defined (NeXT)
655 /* The NeXT code was adapted from iscreen 3.2. */
658 struct processor_set_basic_info info;
661 /* We only know how to get the 1-minute average for this system,
662 so even if the caller asks for more than 1, we only return 1. */
664 if (!getloadavg_initialized)
666 if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS)
667 getloadavg_initialized = 1;
670 if (getloadavg_initialized)
672 info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
673 if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host,
674 (processor_set_info_t) &info, &info_count)
676 getloadavg_initialized = 0;
680 loadavg[elem++] = (double) info.load_average / LOAD_SCALE;
684 if (!getloadavg_initialized)
688 #if !defined (LDAV_DONE) && defined (UMAX)
690 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not
691 have a /dev/kmem. Information about the workings of the running kernel
692 can be gathered with inq_stats system calls.
693 We only know how to get the 1-minute average for this system. */
695 struct proc_summary proc_sum_data;
696 struct stat_descr proc_info;
698 REGISTER unsigned int i, j;
702 REGISTER unsigned int c, i;
703 struct cpu_config conf;
704 struct stat_descr desc;
707 desc.sd_subsys = SUBSYS_CPU;
708 desc.sd_type = CPUTYPE_CONFIG;
709 desc.sd_addr = (char *) &conf;
710 desc.sd_size = sizeof conf;
712 if (inq_stats (1, &desc))
716 for (i = 0; i < conf.config_maxclass; ++i)
718 struct class_stats stats;
719 memset ((char *) &stats, 0, sizeof stats);
721 desc.sd_type = CPUTYPE_CLASS;
723 desc.sd_addr = (char *) &stats;
724 desc.sd_size = sizeof stats;
726 if (inq_stats (1, &desc))
729 c += stats.class_numcpus;
732 samples = cpus < 2 ? 3 : (2 * cpus / 3);
735 proc_info.sd_next = 0;
736 proc_info.sd_subsys = SUBSYS_PROC;
737 proc_info.sd_type = PROCTYPE_SUMMARY;
738 proc_info.sd_addr = (char *) &proc_sum_data;
739 proc_info.sd_size = sizeof (struct proc_summary);
740 proc_info.sd_sizeused = 0;
742 if (inq_stats (1, &proc_info) != 0)
745 load = proc_sum_data.ps_nrunnable;
747 for (i = samples - 1; i > 0; --i)
749 load += proc_sum_data.ps_nrun[j];
750 if (j++ == PS_NRUNSIZE)
755 loadavg[elem++] = load / samples / cpus;
758 #if !defined (LDAV_DONE) && defined (DGUX)
760 /* This call can return -1 for an error, but with good args
761 it's not supposed to fail. The first argument is for no
762 apparent reason of type `long int *'. */
763 dg_sys_info ((long int *) &load_info,
764 DG_SYS_INFO_LOAD_INFO_TYPE,
765 DG_SYS_INFO_LOAD_VERSION_0);
768 loadavg[elem++] = load_info.one_minute;
770 loadavg[elem++] = load_info.five_minute;
772 loadavg[elem++] = load_info.fifteen_minute;
775 #if !defined (LDAV_DONE) && defined (apollo)
777 /* Apollo code from lisch@mentorg.com (Ray Lischner).
779 This system call is not documented. The load average is obtained as
780 three long integers, for the load average over the past minute,
781 five minutes, and fifteen minutes. Each value is a scaled integer,
782 with 16 bits of integer part and 16 bits of fraction part.
784 I'm not sure which operating system first supported this system call,
785 but I know that SR10.2 supports it. */
787 extern void proc1_$get_loadav ();
788 unsigned long load_ave[3];
790 proc1_$get_loadav (load_ave);
793 loadavg[elem++] = load_ave[0] / 65536.0;
795 loadavg[elem++] = load_ave[1] / 65536.0;
797 loadavg[elem++] = load_ave[2] / 65536.0;
800 #if !defined (LDAV_DONE) && defined (OSF_MIPS)
803 struct tbl_loadavg load_ave;
804 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
806 = (load_ave.tl_lscale == 0
807 ? load_ave.tl_avenrun.d[0]
808 : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale));
809 #endif /* OSF_MIPS */
811 #if !defined (LDAV_DONE) && (defined (MSDOS) || defined (WIN32))
814 /* A faithful emulation is going to have to be saved for a rainy day. */
815 for ( ; elem < nelem; elem++)
821 #if !defined (LDAV_DONE) && defined (OSF_ALPHA)
824 struct tbl_loadavg load_ave;
825 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave));
826 for (elem = 0; elem < nelem; elem++)
828 = (load_ave.tl_lscale == 0
829 ? load_ave.tl_avenrun.d[elem]
830 : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale));
831 #endif /* OSF_ALPHA */
833 #if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE)
835 /* UNIX-specific code -- read the average from /dev/kmem. */
837 #define LDAV_PRIVILEGED /* This code requires special installation. */
839 LOAD_AVE_TYPE load_ave[3];
841 /* Get the address of LDAV_SYMBOL. */
846 strcpy (nl[0].n_name, LDAV_SYMBOL);
847 strcpy (nl[1].n_name, "");
848 #else /* NLIST_STRUCT */
849 #ifdef NLIST_NAME_UNION
850 nl[0].n_un.n_name = LDAV_SYMBOL;
851 nl[1].n_un.n_name = 0;
852 #else /* not NLIST_NAME_UNION */
853 nl[0].n_name = (char *) LDAV_SYMBOL;
855 #endif /* not NLIST_NAME_UNION */
856 #endif /* NLIST_STRUCT */
860 #if !(defined (_AIX) && !defined (ps2))
861 nlist (KERNEL_FILE, nl)
863 knlist (nl, 1, sizeof (nl[0]))
866 /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */
868 #ifdef FIXUP_KERNEL_SYMBOL_ADDR
869 FIXUP_KERNEL_SYMBOL_ADDR (nl);
871 offset = nl[0].n_value;
873 #endif /* !SUNOS_5 */
877 ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN);
879 offset = (long) ldav_off & 0x7fffffff;
883 /* Make sure we have /dev/kmem open. */
884 if (!getloadavg_initialized)
887 channel = open ("/dev/kmem", 0);
890 /* Set the channel to close on exec, so it does not
891 litter any child's descriptor table. */
896 (void) fcntl (channel, F_SETFD, FD_CLOEXEC);
898 getloadavg_initialized = 1;
901 /* We pass 0 for the kernel, corefile, and swapfile names
902 to use the currently running kernel. */
903 kd = kvm_open (0, 0, 0, O_RDONLY, 0);
906 /* nlist the currently running kernel. */
908 offset = nl[0].n_value;
909 getloadavg_initialized = 1;
914 /* If we can, get the load average values. */
915 if (offset && getloadavg_initialized)
917 /* Try to read the load. */
919 if (lseek (channel, offset, 0) == -1L
920 || read (channel, (char *) load_ave, sizeof (load_ave))
921 != sizeof (load_ave))
924 getloadavg_initialized = 0;
927 if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave))
928 != sizeof (load_ave))
931 getloadavg_initialized = 0;
936 if (offset == 0 || !getloadavg_initialized)
940 loadavg[elem++] = LDAV_CVT (load_ave[0]);
942 loadavg[elem++] = LDAV_CVT (load_ave[1]);
944 loadavg[elem++] = LDAV_CVT (load_ave[2]);
947 #endif /* !LDAV_DONE && LOAD_AVE_TYPE */
952 #endif /* ! HAVE_GETLOADAVG */
956 main (int argc, char **argv)
961 naptime = atoi (argv[1]);
968 errno = 0; /* Don't be misled if it doesn't set errno. */
969 loads = getloadavg (avg, 3);
972 perror ("Error getting load average");
976 printf ("1-minute: %f ", avg[0]);
978 printf ("5-minute: %f ", avg[1]);
980 printf ("15-minute: %f ", avg[2]);
995 /* Emulate getloadavg. */
997 getloadavg (double loadavg[], int nelem)
1001 /* A faithful emulation is going to have to be saved for a rainy day. */
1002 for (i = 0; i < nelem; i++)
1009 #endif /*__GNUWIN32__*/
1010 #endif /* WINDOWSNT */