1*59336Sbostic /* 2*59336Sbostic * loadst -- print current time and load statistics. 3*59336Sbostic * -- James Gosling @ CMU, May 1981 4*59336Sbostic * loadst [ -n ] [ interval ] 5*59336Sbostic */ 6*59336Sbostic 7*59336Sbostic #define NO_SHORTNAMES /* Do not want config to try to include remap.h */ 8*59336Sbostic #include "../src/config.h" 9*59336Sbostic #include <stdio.h> 10*59336Sbostic #include <pwd.h> 11*59336Sbostic 12*59336Sbostic /* Define two macros KERNEL_FILE (file to find kernel symtab in) 13*59336Sbostic and LDAV_SYMBOL (symbol name to look for), based on system type. 14*59336Sbostic Also define NLIST_STRUCT if the type `nlist' is a structure we 15*59336Sbostic can get from nlist.h; otherwise must use a.out.h and initialize 16*59336Sbostic with strcpy. Note that config.h may define NLIST_STRUCT 17*59336Sbostic for more modern USG systems. */ 18*59336Sbostic 19*59336Sbostic 20*59336Sbostic #ifdef LOAD_AVE_TYPE 21*59336Sbostic #ifndef NLIST_STRUCT 22*59336Sbostic #include <a.out.h> 23*59336Sbostic #else /* NLIST_STRUCT */ 24*59336Sbostic #include <nlist.h> 25*59336Sbostic #endif /* NLIST_STRUCT */ 26*59336Sbostic #endif /* LOAD_AVE_TYPE */ 27*59336Sbostic 28*59336Sbostic /* All this serves to #include <param.h> and clean up the consequences. */ 29*59336Sbostic #ifdef BSD 30*59336Sbostic /* It appears param.h defines BSD and BSD4_3 in 4.3 31*59336Sbostic and is not considerate enough to avoid bombing out 32*59336Sbostic if they are already defined. */ 33*59336Sbostic #undef BSD 34*59336Sbostic #ifdef BSD4_3 35*59336Sbostic #undef BSD4_3 36*59336Sbostic #define XBSD4_3 /* XBSD4_3 says BSD4_3 is supposed to be defined. */ 37*59336Sbostic #endif 38*59336Sbostic #include <sys/param.h> 39*59336Sbostic /* Now if BSD or BSD4_3 was defined and is no longer, 40*59336Sbostic define it again. */ 41*59336Sbostic #ifndef BSD 42*59336Sbostic #define BSD 43*59336Sbostic #endif 44*59336Sbostic #ifdef XBSD4_3 45*59336Sbostic #ifndef BSD4_3 46*59336Sbostic #define BSD4_3 47*59336Sbostic #endif 48*59336Sbostic #endif /* XBSD4_3 */ 49*59336Sbostic #endif /* BSD */ 50*59336Sbostic 51*59336Sbostic #ifdef USG 52*59336Sbostic #include <time.h> 53*59336Sbostic #include <sys/types.h> 54*59336Sbostic #else /* not USG */ 55*59336Sbostic #include <sys/time.h> 56*59336Sbostic #ifdef LOAD_AVE_TYPE 57*59336Sbostic #ifndef RTU 58*59336Sbostic #ifndef UMAX 59*59336Sbostic #ifdef DKSTAT_HEADER_FILE 60*59336Sbostic #include <sys/dkstat.h> 61*59336Sbostic #else 62*59336Sbostic #include <sys/dk.h> 63*59336Sbostic #endif /* not DKSTAT_HEADER_FILE */ 64*59336Sbostic #endif /* UMAX */ 65*59336Sbostic #endif /* not RTU */ 66*59336Sbostic #endif /* LOAD_AVE_TYPE */ 67*59336Sbostic #endif /* USG */ 68*59336Sbostic 69*59336Sbostic #include <sys/stat.h> 70*59336Sbostic 71*59336Sbostic #ifdef BSD 72*59336Sbostic #include <sys/ioctl.h> 73*59336Sbostic #endif /* BSD */ 74*59336Sbostic 75*59336Sbostic #ifdef UMAX 76*59336Sbostic /* 77*59336Sbostic * UMAX 4.2, which runs on the Encore Multimax multiprocessor, does not 78*59336Sbostic * have a /dev/kmem. Information about the workings of the running kernel 79*59336Sbostic * can be gathered with inq_stats system calls. 80*59336Sbostic */ 81*59336Sbostic #include <sys/sysdefs.h> 82*59336Sbostic #include <sys/syscall.h> 83*59336Sbostic #include <sys/statistics.h> 84*59336Sbostic #include <sys/procstats.h> 85*59336Sbostic #include <sys/sysstats.h> 86*59336Sbostic #endif /* UMAX */ 87*59336Sbostic 88*59336Sbostic /* We don't want Emacs's macro definitions for these USG primitives. */ 89*59336Sbostic 90*59336Sbostic #undef open 91*59336Sbostic #undef read 92*59336Sbostic #undef close 93*59336Sbostic 94*59336Sbostic struct tm *localtime (); 95*59336Sbostic 96*59336Sbostic #ifndef DKXFER_SYMBOL 97*59336Sbostic #define DKXFER_SYMBOL "_dk_xfer" 98*59336Sbostic #endif 99*59336Sbostic #ifndef CPTIME_SYMBOL 100*59336Sbostic #define CPTIME_SYMBOL "_cp_time" 101*59336Sbostic #endif 102*59336Sbostic 103*59336Sbostic #ifdef LOAD_AVE_TYPE 104*59336Sbostic #ifndef NLIST_STRUCT 105*59336Sbostic struct nlist nl[2]; 106*59336Sbostic #else /* NLIST_STRUCT */ 107*59336Sbostic struct nlist nl[] = 108*59336Sbostic { 109*59336Sbostic { LDAV_SYMBOL }, 110*59336Sbostic #if defined (CPUSTATES) && defined (DK_NDRIVE) 111*59336Sbostic #define X_CPTIME 1 112*59336Sbostic { CPTIME_SYMBOL }, 113*59336Sbostic #define X_DKXFER 2 114*59336Sbostic { DKXFER_SYMBOL }, 115*59336Sbostic #endif /* have CPUSTATES and DK_NDRIVE */ 116*59336Sbostic { 0 }, 117*59336Sbostic }; 118*59336Sbostic #endif /* NLIST_STRUCT */ 119*59336Sbostic #endif /* LOAD_AVE_TYPE */ 120*59336Sbostic 121*59336Sbostic #if defined (CPUSTATES) && defined (DK_NDRIVE) 122*59336Sbostic 123*59336Sbostic struct 124*59336Sbostic { 125*59336Sbostic long time[CPUSTATES]; 126*59336Sbostic long xfer[DK_NDRIVE]; 127*59336Sbostic } s, s1; 128*59336Sbostic 129*59336Sbostic double etime; 130*59336Sbostic 131*59336Sbostic #endif /* have CPUSTATES and DK_NDRIVE */ 132*59336Sbostic 133*59336Sbostic int nflag; /* -n flag -- no newline */ 134*59336Sbostic int uflag; /* -u flag -- user current user ID rather 135*59336Sbostic than login user ID */ 136*59336Sbostic int repetition; /* repetition interval */ 137*59336Sbostic 138*59336Sbostic #ifdef LOAD_AVE_TYPE 139*59336Sbostic LOAD_AVE_TYPE load_average (); 140*59336Sbostic #endif /* LOAD_AVE_TYPE */ 141*59336Sbostic 142*59336Sbostic main (argc, argv) 143*59336Sbostic char **argv; 144*59336Sbostic { 145*59336Sbostic register int kmem, i; 146*59336Sbostic char *mail; 147*59336Sbostic char *user_name; 148*59336Sbostic struct stat st; 149*59336Sbostic #ifdef LOAD_AVE_TYPE 150*59336Sbostic LOAD_AVE_TYPE load; 151*59336Sbostic #endif /* LOAD_AVE_TYPE */ 152*59336Sbostic 153*59336Sbostic kmem = open ("/dev/kmem", 0); 154*59336Sbostic 155*59336Sbostic #ifdef LOAD_AVE_TYPE 156*59336Sbostic #ifndef NLIST_STRUCT 157*59336Sbostic strcpy (nl[0].n_name, LDAV_SYMBOL); 158*59336Sbostic strcpy (nl[1].n_name, ""); 159*59336Sbostic #endif /* not NLIST_STRUCT */ 160*59336Sbostic 161*59336Sbostic nlist (KERNEL_FILE, nl); 162*59336Sbostic #endif /* LOAD_AVE_TYPE */ 163*59336Sbostic 164*59336Sbostic while (--argc > 0) 165*59336Sbostic { 166*59336Sbostic argv++; 167*59336Sbostic if (strcmp (*argv, "-n") == 0) 168*59336Sbostic nflag++; 169*59336Sbostic else if (strcmp (*argv, "-u") == 0) 170*59336Sbostic uflag++; 171*59336Sbostic else 172*59336Sbostic if ((repetition = atoi (*argv)) <= 0) 173*59336Sbostic { 174*59336Sbostic fprintf (stderr, "Bogus argument: %s\n", *argv); 175*59336Sbostic exit (1); 176*59336Sbostic } 177*59336Sbostic } 178*59336Sbostic 179*59336Sbostic user_name = uflag ? ((struct passwd *) getpwuid (getuid ())) -> pw_name 180*59336Sbostic #ifdef USG 181*59336Sbostic : (char *) getenv ("LOGNAME"); 182*59336Sbostic #else 183*59336Sbostic : (char *) getenv ("USER"); 184*59336Sbostic #endif 185*59336Sbostic 186*59336Sbostic mail = (char *) getenv ("MAIL"); 187*59336Sbostic 188*59336Sbostic if (mail == 0) 189*59336Sbostic { 190*59336Sbostic mail = (char *) malloc (strlen (user_name) + 30); 191*59336Sbostic 192*59336Sbostic #if defined (USG) && ! defined (XENIX) 193*59336Sbostic sprintf (mail, "/usr/mail/%s", user_name); 194*59336Sbostic #else /* Xenix, or not USG */ 195*59336Sbostic sprintf (mail, "/usr/spool/mail/%s", user_name); 196*59336Sbostic #endif /* Xenix, or not USG */ 197*59336Sbostic } 198*59336Sbostic 199*59336Sbostic if (stat (mail, &st) >= 0 200*59336Sbostic && (st.st_mode & S_IFMT) == S_IFDIR) 201*59336Sbostic { 202*59336Sbostic strcat (mail, "/"); 203*59336Sbostic strcat (mail, user_name); 204*59336Sbostic } 205*59336Sbostic 206*59336Sbostic while (1) 207*59336Sbostic { 208*59336Sbostic register struct tm *nowt; 209*59336Sbostic long now; 210*59336Sbostic 211*59336Sbostic time (&now); 212*59336Sbostic nowt = localtime (&now); 213*59336Sbostic 214*59336Sbostic printf ("%d:%02d%s ", 215*59336Sbostic ((nowt->tm_hour + 11) % 12) + 1, 216*59336Sbostic nowt->tm_min, 217*59336Sbostic nowt->tm_hour >= 12 ? "pm" : "am"); 218*59336Sbostic 219*59336Sbostic #ifdef LOAD_AVE_TYPE 220*59336Sbostic load = load_average (kmem); 221*59336Sbostic if (load != (LOAD_AVE_TYPE) -1) 222*59336Sbostic printf("%.2f", LOAD_AVE_CVT (load) / 100.0); 223*59336Sbostic #endif /* LOAD_AVE_TYPE */ 224*59336Sbostic 225*59336Sbostic printf ("%s", 226*59336Sbostic ((stat (mail, &st) >= 0 && st.st_size > 0) 227*59336Sbostic ? " Mail" 228*59336Sbostic : "")); 229*59336Sbostic 230*59336Sbostic #if defined (CPUSTATES) && defined (DK_NDRIVE) 231*59336Sbostic if (kmem >= 0) 232*59336Sbostic { 233*59336Sbostic lseek (kmem, (long) nl[X_CPTIME].n_value, 0); 234*59336Sbostic read (kmem, s.time, sizeof s.time); 235*59336Sbostic lseek (kmem, (long) nl[X_DKXFER].n_value, 0); 236*59336Sbostic read (kmem, s.xfer, sizeof s.xfer); 237*59336Sbostic etime = 0; 238*59336Sbostic for (i = 0; i < DK_NDRIVE; i++) 239*59336Sbostic { 240*59336Sbostic register t = s.xfer[i]; 241*59336Sbostic s.xfer[i] -= s1.xfer[i]; 242*59336Sbostic s1.xfer[i] = t; 243*59336Sbostic } 244*59336Sbostic #ifndef BSD4_3 245*59336Sbostic for (i = 0; i < CPUSTATES; i++) 246*59336Sbostic { 247*59336Sbostic register t = s.time[i]; 248*59336Sbostic s.time[i] -= s1.time[i]; 249*59336Sbostic s1.time[i] = t; 250*59336Sbostic etime += s.time[i]; 251*59336Sbostic } 252*59336Sbostic if (etime == 0.) 253*59336Sbostic etime = 1.; 254*59336Sbostic etime /= 60.; 255*59336Sbostic 256*59336Sbostic #else 257*59336Sbostic { 258*59336Sbostic static struct timeval tv, tv1; 259*59336Sbostic gettimeofday (&tv, 0); 260*59336Sbostic etime = (tv.tv_sec - tv1.tv_sec) 261*59336Sbostic + (tv.tv_usec - tv1.tv_usec) / 1.0e6; 262*59336Sbostic tv1 = tv; 263*59336Sbostic } 264*59336Sbostic #endif 265*59336Sbostic { register max = s.xfer[0]; 266*59336Sbostic for (i = 1; i < DK_NDRIVE; i++) 267*59336Sbostic if (s.xfer[i] > max) 268*59336Sbostic max = s.xfer[i]; 269*59336Sbostic printf ("[%d]", (int) (max / etime + 0.5)); 270*59336Sbostic } 271*59336Sbostic } 272*59336Sbostic #endif /* have CPUSTATES and DK_NDRIVE */ 273*59336Sbostic if (!nflag) 274*59336Sbostic putchar ('\n'); 275*59336Sbostic fflush (stdout); 276*59336Sbostic if (repetition <= 0) 277*59336Sbostic break; 278*59336Sbostic sleep (repetition); 279*59336Sbostic 280*59336Sbostic #ifdef BSD 281*59336Sbostic /* We are about to loop back and write another unit of output. */ 282*59336Sbostic /* If previous output has not yet been read by Emacs, flush it 283*59336Sbostic so the pty output buffer never gets full and Emacs 284*59336Sbostic can always get the latest update right away. */ 285*59336Sbostic /* ??? Someone should write a USG version of this code! */ 286*59336Sbostic { 287*59336Sbostic int zero = 0; 288*59336Sbostic 289*59336Sbostic ioctl (fileno (stdout), TIOCFLUSH, &zero); 290*59336Sbostic } 291*59336Sbostic #endif 292*59336Sbostic } 293*59336Sbostic } 294*59336Sbostic 295*59336Sbostic #ifdef LOAD_AVE_TYPE 296*59336Sbostic 297*59336Sbostic LOAD_AVE_TYPE 298*59336Sbostic load_average (kmem) 299*59336Sbostic int kmem; 300*59336Sbostic { 301*59336Sbostic #ifdef UMAX 302*59336Sbostic 303*59336Sbostic int i, j; 304*59336Sbostic double sum; 305*59336Sbostic struct proc_summary proc_sum_data; 306*59336Sbostic struct stat_descr proc_info; 307*59336Sbostic 308*59336Sbostic proc_info.sd_next = NULL; 309*59336Sbostic proc_info.sd_subsys = SUBSYS_PROC; 310*59336Sbostic proc_info.sd_type = PROCTYPE_SUMMARY; 311*59336Sbostic proc_info.sd_addr = (char *) &proc_sum_data; 312*59336Sbostic proc_info.sd_size = sizeof (struct proc_summary); 313*59336Sbostic proc_info.sd_sizeused = 0; 314*59336Sbostic 315*59336Sbostic if (inq_stats (1, &proc_info) != 0 ) 316*59336Sbostic { 317*59336Sbostic perror ("sysline proc summary inq_stats"); 318*59336Sbostic exit (1); 319*59336Sbostic } 320*59336Sbostic /* 321*59336Sbostic * Generate current load average. 322*59336Sbostic */ 323*59336Sbostic sum = 0; 324*59336Sbostic for (i = proc_sum_data.ps_nrunidx, j = 0; j < 12; j++) 325*59336Sbostic { 326*59336Sbostic sum += proc_sum_data.ps_nrun[i]; 327*59336Sbostic if (--i < 0) 328*59336Sbostic i = 179; 329*59336Sbostic } 330*59336Sbostic return sum / 12; 331*59336Sbostic 332*59336Sbostic #else /* not UMAX */ 333*59336Sbostic 334*59336Sbostic if (kmem >= 0) 335*59336Sbostic { 336*59336Sbostic LOAD_AVE_TYPE avenrun[3]; 337*59336Sbostic avenrun[0] = 0; 338*59336Sbostic #ifdef HAVE_GETLOADAVG 339*59336Sbostic (void) getloadavg(avenrun, 3); 340*59336Sbostic #else 341*59336Sbostic lseek (kmem, (long) nl[0].n_value, 0); 342*59336Sbostic read (kmem, avenrun, sizeof (avenrun)); 343*59336Sbostic #endif 344*59336Sbostic return avenrun[0]; 345*59336Sbostic } 346*59336Sbostic else 347*59336Sbostic return (LOAD_AVE_TYPE) -1; 348*59336Sbostic 349*59336Sbostic #endif /* UMAX */ 350*59336Sbostic } 351*59336Sbostic 352*59336Sbostic #endif /* LOAD_AVE_TYPE */ 353