ian@sibyl.eleceng.ua.oz.au (01/15/90)
I have extended loadst to cope with SysV style load information and also to flush its output buffer for SysV machines. It requires that LOAD_AVE_TYPE *not* be defined. Behaviour is controlled by the following predefines: USG_SYSINFO /* Unables the whole shebang */ USG_SYSINFO_SYM /* Defaults to "_sysinfo" */ USG_UNIT_STAT /* Turns on disk load information */ USG_UNIT_STAT_SYM /* Defaults to "_unit_stat" NUNITS /* Number of disk units to monitor */ The IO load reported is often very high and I am unsure how it relates to the numbers reported on BSD systems. None the less, it is a number from which you can gain a feeling for whether the system is IO bound or not. The load average never drops below 1 when run from emacs, although when run in isolation on an idle system the loadaverage can approach 0. I think this is an artifact of the way emacs emulates select on a system V box. ------------------------ Cut Here --------------------------------- # This is a shell archive. Remove anything before this line, # then unpack it by saving it in a file and typing "sh file". # # Wrapped by on Mon Jan 15 22:13:24 CDT 1990 # Contents: loadst.c echo x - loadst.c sed 's/^@//' > "loadst.c" <<'@//E*O*F loadst.c//' /* * loadst -- print current time and load statistics. * -- James Gosling @ CMU, May 1981 * loadst [ -n ] [ interval ] */ #define NO_SHORTNAMES /* Do not want config to try to include remap.h */ #include "../src/config.h" #include <stdio.h> #include <pwd.h> /* Define two macros KERNEL_FILE (file to find kernel symtab in) and LDAV_SYMBOL (symbol name to look for), based on system type. Also define NLIST_STRUCT if the type `nlist' is a structure we can get from nlist.h; otherwise must use a.out.h and initialize with strcpy. Note that config.h may define NLIST_STRUCT for more modern USG systems. */ #if defined(LOAD_AVE_TYPE) || defined(USG_SYSINFO) #ifndef NLIST_STRUCT #include <a.out.h> #else /* NLIST_STRUCT */ #include <nlist.h> #endif /* NLIST_STRUCT */ #endif /* LOAD_AVE_TYPE || USG_SYSINFO*/ /* All this serves to #include <param.h> and clean up the consequences. */ #ifdef BSD /* It appears param.h defines BSD and BSD4_3 in 4.3 and is not considerate enough to avoid bombing out if they are already defined. */ #undef BSD #ifdef BSD4_3 #undef BSD4_3 #define XBSD4_3 /* XBSD4_3 says BSD4_3 is supposed to be defined. */ #endif #include <sys/param.h> /* Now if BSD or BSD4_3 was defined and is no longer, define it again. */ #ifndef BSD #define BSD #endif #ifdef XBSD4_3 #ifndef BSD4_3 #define BSD4_3 #endif #endif /* XBSD4_3 */ #endif /* BSD */ #ifdef USG #include <time.h> #include <sys/types.h> #include <sys/param.h> #ifdef USG_SYSINFO #include <sys/sysinfo.h> #ifndef USG_SYSINFO_SYM #define USG_SYSINFO_SYM "_sysinfo" #endif /* USG_SYSINFO_SYM */ #endif /* USG_SYSINFO */ #ifdef USG_UNIT_STAT #include <sys/elog.h> #endif #else /* not USG */ #include <sys/time.h> #ifdef LOAD_AVE_TYPE #ifndef RTU #ifndef UMAX #ifdef DKSTAT_HEADER_FILE #include <sys/dkstat.h> #else #include <sys/dk.h> #endif /* not DKSTAT_HEADER_FILE */ #endif /* UMAX */ #endif /* not RTU */ #endif /* LOAD_AVE_TYPE */ #endif /* USG */ #include <sys/stat.h> #ifdef BSD #include <sys/ioctl.h> #endif /* BSD */ #ifdef USG #include <termio.h> #endif #ifdef UMAX /* * UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not * have a /dev/kmem. Information about the workings of the running kernel * can be gathered with inq_stats system calls. */ #include <sys/sysdefs.h> #include <sys/syscall.h> #include <sys/statistics.h> #include <sys/procstats.h> #include <sys/sysstats.h> #endif /* UMAX */ /* We don't want Emacs's macro definitions for these USG primitives. */ #undef open #undef read #undef close struct tm *localtime (); #ifndef USG_UNIT_STAT #ifndef DKXFER_SYMBOL #define DKXFER_SYMBOL "_dk_xfer" #endif #ifndef CPTIME_SYMBOL #define CPTIME_SYMBOL "_cp_time" #endif #else #ifndef UNIT_STAT_SYM #define UNIT_STAT_SYM "_unit_stat" #endif #endif /* USG_UNIT_STAT */ #if defined(LOAD_AVE_TYPE) || defined(USG_SYSINFO) #ifndef NLIST_STRUCT struct nlist nl[2]; #else /* NLIST_STRUCT */ struct nlist nl[] = { #ifdef LOAD_AVE_TYPE { LDAV_SYMBOL }, #else { USG_SYSINFO_SYM }, #endif #if defined (CPUSTATES) && defined (DK_NDRIVE) #define X_CPTIME 1 { CPTIME_SYMBOL }, #define X_DKXFER 2 { DKXFER_SYMBOL }, #endif /* have CPUSTATES and DK_NDRIVE */ #ifdef USG_UNIT_STAT { UNIT_STAT_SYM }, #endif { 0 }, }; #endif /* NLIST_STRUCT */ #endif /* LOAD_AVE_TYPE */ #if defined (CPUSTATES) && defined (DK_NDRIVE) struct { long time[CPUSTATES]; long xfer[DK_NDRIVE]; } s, s1; double etime; #endif /* have CPUSTATES and DK_NDRIVE */ int nflag; /* -n flag -- no newline */ int uflag; /* -u flag -- user current user ID rather than login user ID */ int repetition; /* repetition interval */ #ifdef LOAD_AVE_TYPE LOAD_AVE_TYPE load_average (); #endif /* LOAD_AVE_TYPE */ #if defined(USG_SYSINFO) || defined(USG_UNIT_STAT) main (argc, argv) char **argv; { register int kmem, i; char *mail; char *user_name; struct stat st; #ifdef LOAD_AVE_TYPE LOAD_AVE_TYPE load; #endif /* LOAD_AVE_TYPE */ #ifdef USG_SYSINFO struct sysinfo current_info, last_info; int valid_last_info = 0; unsigned long elapsed_time; /* in ticks. Divide by HZ to get seconds. */ #endif #ifdef USG_UNIT_STAT struct iotime current_unit_stat[NUNITS], last_unit_stat[NUNITS]; int valid_last_iostat = 0; #endif kmem = open ("/dev/kmem", 0); #if defined(LOAD_AVE_TYPE) || defined(USG_SYSINFO) #ifndef NLIST_STRUCT strcpy (nl[0].n_name, LDAV_SYMBOL); strcpy (nl[1].n_name, ""); #endif /* not NLIST_STRUCT */ nlist (KERNEL_FILE, nl); #endif /* LOAD_AVE_TYPE */ while (--argc > 0) { argv++; if (strcmp (*argv, "-n") == 0) nflag++; else if (strcmp (*argv, "-u") == 0) uflag++; else if ((repetition = atoi (*argv)) <= 0) { fprintf (stderr, "Bogus argument: %s\n", *argv); exit (1); } } user_name = uflag ? ((struct passwd *) getpwuid (getuid ())) -> pw_name #ifdef USG : (char *) getenv ("LOGNAME"); #else : (char *) getenv ("USER"); #endif mail = (char *) getenv ("MAIL"); if (mail == 0) { mail = (char *) malloc (strlen (user_name) + 30); #if defined (USG) && ! defined (XENIX) sprintf (mail, "/usr/mail/%s", user_name); #else /* Xenix, or not USG */ sprintf (mail, "/usr/spool/mail/%s", user_name); #endif /* Xenix, or not USG */ } if (stat (mail, &st) >= 0 && (st.st_mode & S_IFMT) == S_IFDIR) { strcat (mail, "/"); strcat (mail, user_name); } while (1) { register struct tm *nowt; long now; time (&now); nowt = localtime (&now); printf ("%d:%02d%s ", ((nowt->tm_hour + 11) % 12) + 1, nowt->tm_min, nowt->tm_hour >= 12 ? "pm" : "am"); #ifdef LOAD_AVE_TYPE load = load_average (kmem); if (load != (LOAD_AVE_TYPE) -1) printf("%.2f", LOAD_AVE_CVT (load) / 100.0); #endif /* LOAD_AVE_TYPE */ #ifdef USG_SYSINFO if (kmem >= 0) { register long temp; lseek (kmem, (long) nl[0].n_value, 0); read (kmem, ¤t_info, sizeof (current_info)); temp = current_info.runque; current_info.runque -= last_info.runque; last_info.runque = temp; for (i = 0, elapsed_time = 0; i < 4; i++) { temp = current_info.cpu[i]; current_info.cpu[i] -= last_info.cpu[i]; last_info.cpu[i] = temp; elapsed_time += current_info.cpu[i]; } elapsed_time = elapsed_time? elapsed_time: 1; if (valid_last_info) printf("%.2f", ((double) current_info.runque * HZ)/elapsed_time); valid_last_info = 1; } #endif /* USG_SYSINFO */ printf ("%s", ((stat (mail, &st) >= 0 && st.st_size > 0) ? " Mail" : "")); #if defined (CPUSTATES) && defined (DK_NDRIVE) if (kmem >= 0) { lseek (kmem, (long) nl[X_CPTIME].n_value, 0); read (kmem, s.time, sizeof s.time); lseek (kmem, (long) nl[X_DKXFER].n_value, 0); read (kmem, s.xfer, sizeof s.xfer); etime = 0; for (i = 0; i < DK_NDRIVE; i++) { register t = s.xfer[i]; s.xfer[i] -= s1.xfer[i]; s1.xfer[i] = t; } for (i = 0; i < CPUSTATES; i++) { register t = s.time[i]; s.time[i] -= s1.time[i]; s1.time[i] = t; etime += s.time[i]; } if (etime == 0.) etime = 1.; etime /= 60.; { register max = s.xfer[0]; for (i = 1; i < DK_NDRIVE; i++) if (s.xfer[i] > max) max = s.xfer[i]; printf ("[%d]", (int) (max / etime + 0.5)); } } #endif /* have CPUSTATES and DK_NDRIVE */ /* We need the elapsed time from USG_SYSINFO for this code to make sense */ #if defined(USG_UNIT_STAT) && defined(USG_SYSINFO) if (kmem >= 0) { long max = 0; lseek (kmem, (long) nl[1].n_value, 0); read (kmem, current_unit_stat, sizeof (current_unit_stat)); for (i = 0; i < NUNITS; i++) { register time_t temp; temp = current_unit_stat[i].io_resp; current_unit_stat[i].io_resp -= last_unit_stat[i].io_resp; last_unit_stat[i].io_resp = temp; if (current_unit_stat[i].io_resp > max) max = current_unit_stat[i].io_resp; } if (valid_last_iostat) printf ("[%d]", (int) (((float) max * HZ) / elapsed_time + 0.5)); valid_last_iostat = 1; } #endif /* USG_UNIT_STAT */ if (!nflag) putchar ('\n'); fflush (stdout); if (repetition <= 0) break; sleep (repetition); #ifdef BSD /* We are about to loop back and write another unit of output. */ /* If previous output has not yet been read by Emacs, flush it so the pty output buffer never gets full and Emacs can always get the latest update right away. */ /* ??? Someone should write a USG version of this code! */ { int zero = 0; ioctl (fileno (stdout), TIOCFLUSH, &zero); } #endif #if defined(USG) && defined(HAVE_PTYS) /* This does no good except when the output is a tty. */ ioctl (fileno (stdout), TCFLSH, 1); #endif } } #ifdef LOAD_AVE_TYPE LOAD_AVE_TYPE load_average (kmem) int kmem; { #ifdef UMAX int i, j; double sum; struct proc_summary proc_sum_data; struct stat_descr proc_info; proc_info.sd_next = NULL; proc_info.sd_subsys = SUBSYS_PROC; proc_info.sd_type = PROCTYPE_SUMMARY; proc_info.sd_addr = (char *) &proc_sum_data; proc_info.sd_size = sizeof (struct proc_summary); proc_info.sd_sizeused = 0; if (inq_stats (1, &proc_info) != 0 ) { perror ("sysline proc summary inq_stats"); exit (1); } /* * Generate current load average. */ sum = 0; for (i = proc_sum_data.ps_nrunidx, j = 0; j < 12; j++) { sum += proc_sum_data.ps_nrun[i]; if (--i < 0) i = 179; } return sum / 12; #else /* not UMAX */ if (kmem >= 0) { LOAD_AVE_TYPE avenrun[3]; avenrun[0] = 0; lseek (kmem, (long) nl[0].n_value, 0); read (kmem, avenrun, sizeof (avenrun)); return avenrun[0]; } else return (LOAD_AVE_TYPE) -1; #endif /* UMAX */ } #endif /* LOAD_AVE_TYPE */ @//E*O*F loadst.c// chmod u=rw,g=r,o=r loadst.c exit 0 -------------------------- Cut Here ------------------------------------