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