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