1 /* Get the system load averages. 2 Copyright (C) 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 3 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free 4 Software Foundation, Inc. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License along with 17 this program; see the file COPYING. If not, write to the Free Software 18 Foundation, 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 99 extern 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 (at) 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 (at) 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 462 /* Avoid static vars inside a function since in HPUX they dump as pure. */ 463 464 # ifdef NeXT 465 static processor_set_t default_set; 466 static int getloadavg_initialized; 467 # endif /* NeXT */ 468 469 # ifdef UMAX 470 static unsigned int cpus = 0; 471 static unsigned int samples; 472 # endif /* UMAX */ 473 474 # ifdef DGUX 475 static struct dg_sys_info_load_info load_info; /* what-a-mouthful! */ 476 # endif /* DGUX */ 477 478 #if !defined(HAVE_LIBKSTAT) && defined(LOAD_AVE_TYPE) 479 /* File descriptor open to /dev/kmem or VMS load ave driver. */ 480 static int channel; 481 /* Nonzero iff channel is valid. */ 482 static int getloadavg_initialized; 483 /* Offset in kmem to seek to read load average, or 0 means invalid. */ 484 static long offset; 485 486 #if !defined(VMS) && !defined(sgi) && !defined(__linux__) 487 static struct nlist nl[2]; 488 #endif /* Not VMS or sgi */ 489 490 #ifdef SUNOS_5 491 static kvm_t *kd; 492 #endif /* SUNOS_5 */ 493 494 #endif /* LOAD_AVE_TYPE && !HAVE_LIBKSTAT */ 495 496 /* Put the 1 minute, 5 minute and 15 minute load averages 498 into the first NELEM elements of LOADAVG. 499 Return the number written (never more than 3, but may be less than NELEM), 500 or -1 if an error occurred. */ 501 502 int 503 getloadavg (double loadavg[], int nelem) 504 { 505 int elem = 0; /* Return value. */ 506 507 # ifdef NO_GET_LOAD_AVG 508 # define LDAV_DONE 509 /* Set errno to zero to indicate that there was no particular error; 510 this function just can't work at all on this system. */ 511 errno = 0; 512 elem = -1; 513 # endif 514 515 # if !defined (LDAV_DONE) && defined (HAVE_LIBKSTAT) 516 /* Use libkstat because we don't have to be root. */ 517 # define LDAV_DONE 518 kstat_ctl_t *kc; 519 kstat_t *ksp; 520 kstat_named_t *kn; 521 522 kc = kstat_open (); 523 if (kc == 0) 524 return -1; 525 ksp = kstat_lookup (kc, "unix", 0, "system_misc"); 526 if (ksp == 0 ) 527 return -1; 528 if (kstat_read (kc, ksp, 0) == -1) 529 return -1; 530 531 532 kn = kstat_data_lookup (ksp, "avenrun_1min"); 533 if (kn == 0) 534 { 535 /* Return -1 if no load average information is available. */ 536 nelem = 0; 537 elem = -1; 538 } 539 540 if (nelem >= 1) 541 loadavg[elem++] = (double) kn->value.ul/FSCALE; 542 543 if (nelem >= 2) 544 { 545 kn = kstat_data_lookup (ksp, "avenrun_5min"); 546 if (kn != 0) 547 { 548 loadavg[elem++] = (double) kn->value.ul/FSCALE; 549 550 if (nelem >= 3) 551 { 552 kn = kstat_data_lookup (ksp, "avenrun_15min"); 553 if (kn != 0) 554 loadavg[elem++] = (double) kn->value.ul/FSCALE; 555 } 556 } 557 } 558 559 kstat_close (kc); 560 # endif /* HAVE_LIBKSTAT */ 561 562 # if !defined (LDAV_DONE) && defined (hpux) && defined (HAVE_PSTAT_GETDYNAMIC) 563 /* Use pstat_getdynamic() because we don't have to be root. */ 564 # define LDAV_DONE 565 # undef LOAD_AVE_TYPE 566 567 struct pst_dynamic dyn_info; 568 if (pstat_getdynamic (&dyn_info, sizeof (dyn_info), 0, 0) < 0) 569 return -1; 570 if (nelem > 0) 571 loadavg[elem++] = dyn_info.psd_avg_1_min; 572 if (nelem > 1) 573 loadavg[elem++] = dyn_info.psd_avg_5_min; 574 if (nelem > 2) 575 loadavg[elem++] = dyn_info.psd_avg_15_min; 576 577 # endif /* hpux && HAVE_PSTAT_GETDYNAMIC */ 578 579 # if !defined (LDAV_DONE) && defined (__linux__) 580 # define LDAV_DONE 581 # undef LOAD_AVE_TYPE 582 583 # ifndef LINUX_LDAV_FILE 584 # define LINUX_LDAV_FILE "/proc/loadavg" 585 # endif 586 587 char ldavgbuf[40]; 588 double load_ave[3]; 589 int fd, count; 590 591 fd = open (LINUX_LDAV_FILE, O_RDONLY); 592 if (fd == -1) 593 return -1; 594 count = read (fd, ldavgbuf, 40); 595 (void) close (fd); 596 if (count <= 0) 597 return -1; 598 599 /* The following sscanf must use the C locale. */ 600 setlocale (LC_NUMERIC, "C"); 601 count = sscanf (ldavgbuf, "%lf %lf %lf", 602 &load_ave[0], &load_ave[1], &load_ave[2]); 603 setlocale (LC_NUMERIC, ""); 604 if (count < 1) 605 return -1; 606 607 for (elem = 0; elem < nelem && elem < count; elem++) 608 loadavg[elem] = load_ave[elem]; 609 610 return elem; 611 612 # endif /* __linux__ */ 613 614 # if !defined (LDAV_DONE) && defined (__NetBSD__) 615 # define LDAV_DONE 616 # undef LOAD_AVE_TYPE 617 618 # ifndef NETBSD_LDAV_FILE 619 # define NETBSD_LDAV_FILE "/kern/loadavg" 620 # endif 621 622 unsigned long int load_ave[3], scale; 623 int count; 624 FILE *fp; 625 626 fp = fopen (NETBSD_LDAV_FILE, "r"); 627 if (fp == NULL) 628 return -1; 629 count = fscanf (fp, "%lu %lu %lu %lu\n", 630 &load_ave[0], &load_ave[1], &load_ave[2], 631 &scale); 632 (void) fclose (fp); 633 if (count != 4) 634 return -1; 635 636 for (elem = 0; elem < nelem; elem++) 637 loadavg[elem] = (double) load_ave[elem] / (double) scale; 638 639 return elem; 640 641 # endif /* __NetBSD__ */ 642 643 # if !defined (LDAV_DONE) && defined (NeXT) 644 # define LDAV_DONE 645 /* The NeXT code was adapted from iscreen 3.2. */ 646 647 host_t host; 648 struct processor_set_basic_info info; 649 unsigned info_count; 650 651 /* We only know how to get the 1-minute average for this system, 652 so even if the caller asks for more than 1, we only return 1. */ 653 654 if (!getloadavg_initialized) 655 { 656 if (processor_set_default (host_self (), &default_set) == KERN_SUCCESS) 657 getloadavg_initialized = 1; 658 } 659 660 if (getloadavg_initialized) 661 { 662 info_count = PROCESSOR_SET_BASIC_INFO_COUNT; 663 if (processor_set_info (default_set, PROCESSOR_SET_BASIC_INFO, &host, 664 (processor_set_info_t) &info, &info_count) 665 != KERN_SUCCESS) 666 getloadavg_initialized = 0; 667 else 668 { 669 if (nelem > 0) 670 loadavg[elem++] = (double) info.load_average / LOAD_SCALE; 671 } 672 } 673 674 if (!getloadavg_initialized) 675 return -1; 676 # endif /* NeXT */ 677 678 # if !defined (LDAV_DONE) && defined (UMAX) 679 # define LDAV_DONE 680 /* UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not 681 have a /dev/kmem. Information about the workings of the running kernel 682 can be gathered with inq_stats system calls. 683 We only know how to get the 1-minute average for this system. */ 684 685 struct proc_summary proc_sum_data; 686 struct stat_descr proc_info; 687 double load; 688 register unsigned int i, j; 689 690 if (cpus == 0) 691 { 692 register unsigned int c, i; 693 struct cpu_config conf; 694 struct stat_descr desc; 695 696 desc.sd_next = 0; 697 desc.sd_subsys = SUBSYS_CPU; 698 desc.sd_type = CPUTYPE_CONFIG; 699 desc.sd_addr = (char *) &conf; 700 desc.sd_size = sizeof conf; 701 702 if (inq_stats (1, &desc)) 703 return -1; 704 705 c = 0; 706 for (i = 0; i < conf.config_maxclass; ++i) 707 { 708 struct class_stats stats; 709 bzero ((char *) &stats, sizeof stats); 710 711 desc.sd_type = CPUTYPE_CLASS; 712 desc.sd_objid = i; 713 desc.sd_addr = (char *) &stats; 714 desc.sd_size = sizeof stats; 715 716 if (inq_stats (1, &desc)) 717 return -1; 718 719 c += stats.class_numcpus; 720 } 721 cpus = c; 722 samples = cpus < 2 ? 3 : (2 * cpus / 3); 723 } 724 725 proc_info.sd_next = 0; 726 proc_info.sd_subsys = SUBSYS_PROC; 727 proc_info.sd_type = PROCTYPE_SUMMARY; 728 proc_info.sd_addr = (char *) &proc_sum_data; 729 proc_info.sd_size = sizeof (struct proc_summary); 730 proc_info.sd_sizeused = 0; 731 732 if (inq_stats (1, &proc_info) != 0) 733 return -1; 734 735 load = proc_sum_data.ps_nrunnable; 736 j = 0; 737 for (i = samples - 1; i > 0; --i) 738 { 739 load += proc_sum_data.ps_nrun[j]; 740 if (j++ == PS_NRUNSIZE) 741 j = 0; 742 } 743 744 if (nelem > 0) 745 loadavg[elem++] = load / samples / cpus; 746 # endif /* UMAX */ 747 748 # if !defined (LDAV_DONE) && defined (DGUX) 749 # define LDAV_DONE 750 /* This call can return -1 for an error, but with good args 751 it's not supposed to fail. The first argument is for no 752 apparent reason of type `long int *'. */ 753 dg_sys_info ((long int *) &load_info, 754 DG_SYS_INFO_LOAD_INFO_TYPE, 755 DG_SYS_INFO_LOAD_VERSION_0); 756 757 if (nelem > 0) 758 loadavg[elem++] = load_info.one_minute; 759 if (nelem > 1) 760 loadavg[elem++] = load_info.five_minute; 761 if (nelem > 2) 762 loadavg[elem++] = load_info.fifteen_minute; 763 # endif /* DGUX */ 764 765 # if !defined (LDAV_DONE) && defined (apollo) 766 # define LDAV_DONE 767 /* Apollo code from lisch (at) mentorg.com (Ray Lischner). 768 769 This system call is not documented. The load average is obtained as 770 three long integers, for the load average over the past minute, 771 five minutes, and fifteen minutes. Each value is a scaled integer, 772 with 16 bits of integer part and 16 bits of fraction part. 773 774 I'm not sure which operating system first supported this system call, 775 but I know that SR10.2 supports it. */ 776 777 extern void proc1_$get_loadav (); 778 unsigned long load_ave[3]; 779 780 proc1_$get_loadav (load_ave); 781 782 if (nelem > 0) 783 loadavg[elem++] = load_ave[0] / 65536.0; 784 if (nelem > 1) 785 loadavg[elem++] = load_ave[1] / 65536.0; 786 if (nelem > 2) 787 loadavg[elem++] = load_ave[2] / 65536.0; 788 # endif /* apollo */ 789 790 # if !defined (LDAV_DONE) && defined (OSF_MIPS) 791 # define LDAV_DONE 792 793 struct tbl_loadavg load_ave; 794 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave)); 795 loadavg[elem++] 796 = (load_ave.tl_lscale == 0 797 ? load_ave.tl_avenrun.d[0] 798 : (load_ave.tl_avenrun.l[0] / (double) load_ave.tl_lscale)); 799 # endif /* OSF_MIPS */ 800 801 # if !defined (LDAV_DONE) && (defined (__MSDOS__) || defined (WINDOWS32)) 802 # define LDAV_DONE 803 804 /* A faithful emulation is going to have to be saved for a rainy day. */ 805 for ( ; elem < nelem; elem++) 806 { 807 loadavg[elem] = 0.0; 808 } 809 # endif /* __MSDOS__ || WINDOWS32 */ 810 811 # if !defined (LDAV_DONE) && defined (OSF_ALPHA) 812 # define LDAV_DONE 813 814 struct tbl_loadavg load_ave; 815 table (TBL_LOADAVG, 0, &load_ave, 1, sizeof (load_ave)); 816 for (elem = 0; elem < nelem; elem++) 817 loadavg[elem] 818 = (load_ave.tl_lscale == 0 819 ? load_ave.tl_avenrun.d[elem] 820 : (load_ave.tl_avenrun.l[elem] / (double) load_ave.tl_lscale)); 821 # endif /* OSF_ALPHA */ 822 823 # if !defined (LDAV_DONE) && defined (VMS) 824 /* VMS specific code -- read from the Load Ave driver. */ 825 826 LOAD_AVE_TYPE load_ave[3]; 827 static int getloadavg_initialized = 0; 828 # ifdef eunice 829 struct 830 { 831 int dsc$w_length; 832 char *dsc$a_pointer; 833 } descriptor; 834 # endif 835 836 /* Ensure that there is a channel open to the load ave device. */ 837 if (!getloadavg_initialized) 838 { 839 /* Attempt to open the channel. */ 840 # ifdef eunice 841 descriptor.dsc$w_length = 18; 842 descriptor.dsc$a_pointer = "$$VMS_LOAD_AVERAGE"; 843 # else 844 $DESCRIPTOR (descriptor, "LAV0:"); 845 # endif 846 if (sys$assign (&descriptor, &channel, 0, 0) & 1) 847 getloadavg_initialized = 1; 848 } 849 850 /* Read the load average vector. */ 851 if (getloadavg_initialized 852 && !(sys$qiow (0, channel, IO$_READVBLK, 0, 0, 0, 853 load_ave, 12, 0, 0, 0, 0) & 1)) 854 { 855 sys$dassgn (channel); 856 getloadavg_initialized = 0; 857 } 858 859 if (!getloadavg_initialized) 860 return -1; 861 # endif /* VMS */ 862 863 # if !defined (LDAV_DONE) && defined(LOAD_AVE_TYPE) && !defined(VMS) 864 865 /* UNIX-specific code -- read the average from /dev/kmem. */ 866 867 # define LDAV_PRIVILEGED /* This code requires special installation. */ 868 869 LOAD_AVE_TYPE load_ave[3]; 870 871 /* Get the address of LDAV_SYMBOL. */ 872 if (offset == 0) 873 { 874 # ifndef sgi 875 # ifndef NLIST_STRUCT 876 strcpy (nl[0].n_name, LDAV_SYMBOL); 877 strcpy (nl[1].n_name, ""); 878 # else /* NLIST_STRUCT */ 879 # ifdef HAVE_STRUCT_NLIST_N_UN_N_NAME 880 nl[0].n_un.n_name = LDAV_SYMBOL; 881 nl[1].n_un.n_name = 0; 882 # else /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */ 883 nl[0].n_name = LDAV_SYMBOL; 884 nl[1].n_name = 0; 885 # endif /* not HAVE_STRUCT_NLIST_N_UN_N_NAME */ 886 # endif /* NLIST_STRUCT */ 887 888 # ifndef SUNOS_5 889 if ( 890 # if !(defined (_AIX) && !defined (ps2)) 891 nlist (KERNEL_FILE, nl) 892 # else /* _AIX */ 893 knlist (nl, 1, sizeof (nl[0])) 894 # endif 895 >= 0) 896 /* Omit "&& nl[0].n_type != 0 " -- it breaks on Sun386i. */ 897 { 898 # ifdef FIXUP_KERNEL_SYMBOL_ADDR 899 FIXUP_KERNEL_SYMBOL_ADDR (nl); 900 # endif 901 offset = nl[0].n_value; 902 } 903 # endif /* !SUNOS_5 */ 904 # else /* sgi */ 905 int ldav_off; 906 907 ldav_off = sysmp (MP_KERNADDR, MPKA_AVENRUN); 908 if (ldav_off != -1) 909 offset = (long) ldav_off & 0x7fffffff; 910 # endif /* sgi */ 911 } 912 913 /* Make sure we have /dev/kmem open. */ 914 if (!getloadavg_initialized) 915 { 916 # ifndef SUNOS_5 917 channel = open ("/dev/kmem", 0); 918 if (channel >= 0) 919 { 920 /* Set the channel to close on exec, so it does not 921 litter any child's descriptor table. */ 922 # ifdef F_SETFD 923 # ifndef FD_CLOEXEC 924 # define FD_CLOEXEC 1 925 # endif 926 (void) fcntl (channel, F_SETFD, FD_CLOEXEC); 927 # endif 928 getloadavg_initialized = 1; 929 } 930 # else /* SUNOS_5 */ 931 /* We pass 0 for the kernel, corefile, and swapfile names 932 to use the currently running kernel. */ 933 kd = kvm_open (0, 0, 0, O_RDONLY, 0); 934 if (kd != 0) 935 { 936 /* nlist the currently running kernel. */ 937 kvm_nlist (kd, nl); 938 offset = nl[0].n_value; 939 getloadavg_initialized = 1; 940 } 941 # endif /* SUNOS_5 */ 942 } 943 944 /* If we can, get the load average values. */ 945 if (offset && getloadavg_initialized) 946 { 947 /* Try to read the load. */ 948 # ifndef SUNOS_5 949 if (lseek (channel, offset, 0) == -1L 950 || read (channel, (char *) load_ave, sizeof (load_ave)) 951 != sizeof (load_ave)) 952 { 953 close (channel); 954 getloadavg_initialized = 0; 955 } 956 # else /* SUNOS_5 */ 957 if (kvm_read (kd, offset, (char *) load_ave, sizeof (load_ave)) 958 != sizeof (load_ave)) 959 { 960 kvm_close (kd); 961 getloadavg_initialized = 0; 962 } 963 # endif /* SUNOS_5 */ 964 } 965 966 if (offset == 0 || !getloadavg_initialized) 967 return -1; 968 # endif /* LOAD_AVE_TYPE and not VMS */ 969 970 # if !defined (LDAV_DONE) && defined (LOAD_AVE_TYPE) /* Including VMS. */ 971 if (nelem > 0) 972 loadavg[elem++] = LDAV_CVT (load_ave[0]); 973 if (nelem > 1) 974 loadavg[elem++] = LDAV_CVT (load_ave[1]); 975 if (nelem > 2) 976 loadavg[elem++] = LDAV_CVT (load_ave[2]); 977 978 # define LDAV_DONE 979 # endif /* !LDAV_DONE && LOAD_AVE_TYPE */ 980 981 # ifdef LDAV_DONE 982 return elem; 983 # else 984 /* Set errno to zero to indicate that there was no particular error; 985 this function just can't work at all on this system. */ 986 errno = 0; 987 return -1; 988 # endif 989 } 990 991 #endif /* ! HAVE_GETLOADAVG */ 992 993 #ifdef TEST 995 #include "make.h" 996 997 int 998 main (int argc, char **argv) 999 { 1000 int naptime = 0; 1001 1002 if (argc > 1) 1003 naptime = atoi (argv[1]); 1004 1005 while (1) 1006 { 1007 double avg[3]; 1008 int loads; 1009 1010 errno = 0; /* Don't be misled if it doesn't set errno. */ 1011 loads = getloadavg (avg, 3); 1012 if (loads == -1) 1013 { 1014 perror ("Error getting load average"); 1015 exit (1); 1016 } 1017 if (loads > 0) 1018 printf ("1-minute: %f ", avg[0]); 1019 if (loads > 1) 1020 printf ("5-minute: %f ", avg[1]); 1021 if (loads > 2) 1022 printf ("15-minute: %f ", avg[2]); 1023 if (loads > 0) 1024 putchar ('\n'); 1025 1026 if (naptime == 0) 1027 break; 1028 sleep (naptime); 1029 } 1030 1031 exit (0); 1032 } 1033 #endif /* TEST */ 1034