BSD 4 release
[unix-history] / usr / src / cmd / sa.c
CommitLineData
31cef89c 1static char *sccsid = "@(#)sa.c 4.1 (Berkeley) 10/1/80";
2efccdb1
BJ
2#include <stdio.h>
3#include <sys/types.h>
4#include <sys/acct.h>
5#include <signal.h>
6
7/* interpret command time accounting */
8
9#define size 2500
10#define NC sizeof(acctbuf.ac_comm)
11struct acct acctbuf;
12int lflg;
13int cflg;
14int Dflg;
15int dflg;
16int iflg;
17int jflg;
18int Kflg;
19int kflg;
20int nflg;
21int aflg;
22int rflg;
23int oflg;
24int tflg;
25int vflg;
26int uflg;
27int thres = 1;
28int sflg;
29int bflg;
30int mflg;
31
32struct user {
33 int us_cnt;
34 double us_ctime;
35 double us_io;
36 double us_imem;
37} user[1000];
38
39struct tab {
40 char name[NC];
41 int count;
42 double realt;
43 double cput;
44 double syst;
45 double imem;
46 double io;
47} tab[size];
48
49double treal;
50double tcpu;
51double tsys;
52double tio;
53double timem;
54int junkp = -1;
55char *sname;
56double ncom;
57time_t expand();
58char *getname();
59
60main(argc, argv)
61char **argv;
62{
63 FILE *ff;
64 int i, j, k;
65 int (*cmp)();
66 extern tcmp(), ncmp(), bcmp(), dcmp(), Dcmp(), kcmp(), Kcmp();
67 extern double sum();
68 double ft;
69
70 cmp = tcmp;
71 if (argc>1)
72 if (argv[1][0]=='-') {
73 argv++;
74 argc--;
75 for(i=1; argv[0][i]; i++)
76 switch(argv[0][i]) {
77
78 case 'o':
79 oflg++;
80 break;
81
82 case 'i':
83 iflg++;
84 break;
85
86 case 'b':
87 bflg++;
88 cmp = bcmp;
89 break;
90
91 case 'l':
92 lflg++;
93 break;
94
95 case 'c':
96 cflg++;
97 break;
98
99 case 'd':
100 dflg++;
101 cmp = dcmp;
102 break;
103
104 case 'D':
105 Dflg++;
106 cmp = Dcmp;
107 break;
108
109 case 'j':
110 jflg++;
111 break;
112
113 case 'k':
114 kflg++;
115 cmp = kcmp;
116 break;
117
118 case 'K':
119 Kflg++;
120 cmp = Kcmp;
121 break;
122
123 case 'n':
124 nflg++;
125 cmp = ncmp;
126 break;
127
128 case 'a':
129 aflg++;
130 break;
131
132 case 'r':
133 rflg++;
134 break;
135
136 case 't':
137 tflg++;
138 break;
139
140 case 's':
141 sflg++;
142 aflg++;
143 break;
144
145 case '0':
146 case '1':
147 case '2':
148 case '3':
149 case '4':
150 case '5':
151 case '6':
152 case '7':
153 case '8':
154 case '9':
155 thres = argv[0][i]-'0';
156 break;
157
158 case 'v':
159 vflg++;
160 break;
161
162 case 'u':
163 uflg++;
164 break;
165
166 case 'm':
167 mflg++;
168 break;
169 }
170 }
171 if (iflg==0)
172 init();
173 if (argc<2)
174 doacct("/usr/adm/acct");
175 else while (--argc)
176 doacct(*++argv);
177 if (uflg) {
178 return;
179 }
180
181/*
182 * cleanup pass
183 * put junk together
184 */
185
186 if (vflg)
187 strip();
188 if(!aflg)
189 for (i=0; i<size; i++)
190 if (tab[i].name[0]) {
191 for(j=0; j<NC; j++)
192 if(tab[i].name[j] == '?')
193 goto yes;
194 if(tab[i].count != 1)
195 continue;
196 yes:
197 if(junkp == -1)
198 junkp = enter("***other");
199 tab[junkp].count += tab[i].count;
200 tab[junkp].realt += tab[i].realt;
201 tab[junkp].cput += tab[i].cput;
202 tab[junkp].syst += tab[i].syst;
203 tab[junkp].imem += tab[i].imem;
204 tab[junkp].io += tab[i].io;
205 tab[i].name[0] = 0;
206 }
207 for(i=k=0; i<size; i++)
208 if(tab[i].name[0]) {
209 tab[k] = tab[i];
210 k++;
211 }
212 if (sflg) {
213 signal(SIGINT, SIG_IGN);
214 if ((ff = fopen("/usr/adm/usracct", "w")) != NULL) {
215 fwrite((char *)user, sizeof(user), 1, ff);
216 fclose(ff);
217 }
218 if ((ff = fopen("/usr/adm/savacct", "w")) == NULL) {
219 printf("Can't save\n");
220 exit(0);
221 }
222 fwrite((char *)tab, sizeof(tab[0]), k, ff);
223 fclose(ff);
224 creat("/usr/adm/acct", 0644);
225 signal(SIGINT, SIG_DFL);
226 }
227/*
228 * sort and print
229 */
230
231 if (mflg) {
232 printmoney();
233 exit(0);
234 }
235 qsort(tab, k, sizeof(tab[0]), cmp);
236 column(ncom, treal, tcpu, tsys, timem, tio);
237 printf("\n");
238 for (i=0; i<k; i++)
239 if (tab[i].name[0]) {
240 ft = tab[i].count;
241 column(ft, tab[i].realt, tab[i].cput, tab[i].syst, tab[i].imem, tab[i].io);
242 printf(" %.14s\n", tab[i].name);
243 }
244}
245
246printmoney()
247{
248 register i;
249 char buf[128];
250 register char *cp;
251
252 for (i=0; i<sizeof(user)/sizeof(user[0]); i++) {
253 if (user[i].us_cnt && user[i].us_ctime) {
254 cp = getname(i);
255 if (cp == 0)
256 printf("%-8d", i);
257 else
258 printf("%-8s", cp);
259 printf("%7u %9.2fcpu %10.0ftio %12.0fk*sec\n",
260 user[i].us_cnt, user[i].us_ctime/60,
261 user[i].us_io,
262 user[i].us_imem / (60 * 2));
263 }
264 }
265}
266
267column(n, a, b, c, d, e)
268double n, a, b, c, d, e;
269{
270
271 printf("%8.0f", n);
272 if(cflg) {
273 if(n == ncom)
274 printf("%9s", ""); else
275 printf("%8.2f%%", 100.*n/ncom);
276 }
277 col(n, a, treal, "re");
278 if (oflg)
279 col(n, 3600*(b/(b+c)), tcpu+tsys, "u/s");
280 else if(lflg) {
281 col(n, b, tcpu, "u");
282 col(n, c, tsys, "s");
283 } else
284 col(n, b+c, tcpu+tsys, "cp");
285 if(tflg)
286 printf("%8.1f", a/(b+c), "re/cp");
287 if(dflg || !Dflg)
288 printf("%10.0favio", e/(n?n:1));
289 else
290 printf("%10.0ftio", e);
291 if (kflg || !Kflg)
292 printf("%10.0fk", d/(2*((b+c)!=0.0?(b+c):1.0)));
293 else
294 printf("%10.0fk*sec", d/(2*60));
295}
296
297col(n, a, m, cp)
298double n, a, m;
299char *cp;
300{
301
302 if(jflg)
303 printf("%11.2f%s", a/(n*60.), cp); else
304 printf("%11.2f%s", a/3600., cp);
305 if(cflg) {
306 if(a == m)
307 printf("%9s", ""); else
308 printf("%8.2f%%", 100.*a/m);
309 }
310}
311
312doacct(f)
313char *f;
314{
315 int i;
316 FILE *ff;
317 long x, y, z;
318 struct acct fbuf;
319 register char *cp;
320 register int c;
321
322 if (sflg && sname) {
323 printf("Only 1 file with -s\n");
324 exit(0);
325 }
326 if (sflg)
327 sname = f;
328 if ((ff = fopen(f, "r"))==NULL) {
329 printf("Can't open %s\n", f);
330 return;
331 }
332 while (fread((char *)&fbuf, sizeof(fbuf), 1, ff) == 1) {
333 if (fbuf.ac_comm[0]==0) {
334 fbuf.ac_comm[0] = '?';
335 }
336 for (cp = fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++) {
337 c = *cp & 0377;
338 if (c && (c < ' ' || c >= 0200)) {
339 *cp = '?';
340 }
341 }
342 if (fbuf.ac_flag&AFORK) {
343 for (cp=fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++)
344 if (*cp==0) {
345 *cp = '*';
346 break;
347 }
348 }
349 x = expand(fbuf.ac_utime) + expand(fbuf.ac_stime);
350 y = fbuf.ac_mem;
351 z = expand(fbuf.ac_io);
352 if (uflg) {
353 printf("%3d%6.1fcp %6dmem %6dio %.14s\n",
354 fbuf.ac_uid, x/60.0, y, z,
355 fbuf.ac_comm);
356 continue;
357 }
358 c = fbuf.ac_uid;
359 user[c].us_cnt++;
360 user[c].us_ctime += x/60.;
361 user[c].us_imem += x * y;
362 user[c].us_io += z;
363 ncom += 1.0;
364 i = enter(fbuf.ac_comm);
365 tab[i].imem += x * y;
366 timem += x * y;
367 tab[i].count++;
368 x = expand(fbuf.ac_etime)*60;
369 tab[i].realt += x;
370 treal += x;
371 x = expand(fbuf.ac_utime);
372 tab[i].cput += x;
373 tcpu += x;
374 x = expand(fbuf.ac_stime);
375 tab[i].syst += x;
376 tsys += x;
377 tab[i].io += z;
378 tio += z;
379 }
380 fclose(ff);
381}
382
383ncmp(p1, p2)
384struct tab *p1, *p2;
385{
386
387 if(p1->count == p2->count)
388 return(tcmp(p1, p2));
389 if(rflg)
390 return(p1->count - p2->count);
391 return(p2->count - p1->count);
392}
393
394bcmp(p1, p2)
395struct tab *p1, *p2;
396{
397 double f1, f2;
398 double sum();
399
400 f1 = sum(p1)/p1->count;
401 f2 = sum(p2)/p2->count;
402 if(f1 < f2) {
403 if(rflg)
404 return(-1);
405 return(1);
406 }
407 if(f1 > f2) {
408 if(rflg)
409 return(1);
410 return(-1);
411 }
412 return(0);
413}
414
415Kcmp(p1, p2)
416struct tab *p1, *p2;
417{
418
419 if (p1->imem < p2->imem) {
420 if(rflg)
421 return(-1);
422 return(1);
423 }
424 if (p1->imem > p2->imem) {
425 if(rflg)
426 return(1);
427 return(-1);
428 }
429 return(0);
430}
431
432kcmp(p1, p2)
433struct tab *p1, *p2;
434{
435 double a1, a2;
436
437 a1 = p1->imem / ((p1->cput+p1->syst)?(p1->cput+p1->syst):1);
438 a2 = p2->imem / ((p2->cput+p2->syst)?(p2->cput+p2->syst):1);
439 if (a1 < a2) {
440 if(rflg)
441 return(-1);
442 return(1);
443 }
444 if (a1 > a2) {
445 if(rflg)
446 return(1);
447 return(-1);
448 }
449 return(0);
450}
451
452dcmp(p1, p2)
453struct tab *p1, *p2;
454{
455 double a1, a2;
456
457 a1 = p1->io / (p1->count?p1->count:1);
458 a2 = p2->io / (p2->count?p2->count:1);
459 if (a1 < a2) {
460 if(rflg)
461 return(-1);
462 return(1);
463 }
464 if (a1 > a2) {
465 if(rflg)
466 return(1);
467 return(-1);
468 }
469 return(0);
470}
471
472Dcmp(p1, p2)
473struct tab *p1, *p2;
474{
475
476 if (p1->io < p2->io) {
477 if(rflg)
478 return(-1);
479 return(1);
480 }
481 if (p1->io > p2->io) {
482 if(rflg)
483 return(1);
484 return(-1);
485 }
486 return(0);
487}
488
489tcmp(p1, p2)
490struct tab *p1, *p2;
491{
492 extern double sum();
493 double f1, f2;
494
495 f1 = sum(p1);
496 f2 = sum(p2);
497 if(f1 < f2) {
498 if(rflg)
499 return(-1);
500 return(1);
501 }
502 if(f1 > f2) {
503 if(rflg)
504 return(1);
505 return(-1);
506 }
507 return(0);
508}
509
510double sum(p)
511struct tab *p;
512{
513
514 if(p->name[0] == 0)
515 return(0.0);
516 return(
517 p->cput+
518 p->syst);
519}
520
521init()
522{
523 struct tab tbuf;
524 int i;
525 FILE *f;
526
527 if ((f = fopen("/usr/adm/savacct", "r")) == NULL)
528 goto gshm;
529 while (fread((char *)&tbuf, sizeof(tbuf), 1, f) == 1) {
530 i = enter(tbuf.name);
531 ncom += tbuf.count;
532 tab[i].count = tbuf.count;
533 treal += tbuf.realt;
534 tab[i].realt = tbuf.realt;
535 tcpu += tbuf.cput;
536 tab[i].cput = tbuf.cput;
537 tsys += tbuf.syst;
538 tab[i].syst = tbuf.syst;
539 tio += tbuf.io;
540 tab[i].io = tbuf.io;
541 timem += tbuf.imem;
542 tab[i].imem = tbuf.imem;
543 }
544 fclose(f);
545 gshm:
546 if ((f = fopen("/usr/adm/usracct", "r")) == NULL)
547 return;
548 fread((char *)user, sizeof(user), 1, f);
549 fclose(f);
550}
551
552enter(np)
553char *np;
554{
555 int i, j;
556
557 for (i=j=0; i<NC; i++) {
558 if (np[i]==0)
559 j = i;
560 if (j)
561 np[i] = 0;
562 }
563 for (i=j=0; j<NC; j++) {
564 i = i*7 + np[j];
565 }
566 if (i < 0)
567 i = -i;
568 for (i%=size; tab[i].name[0]; i = (i+1)%size) {
569 for (j=0; j<NC; j++)
570 if (tab[i].name[j]!=np[j])
571 goto no;
572 goto yes;
573 no:;
574 }
575 for (j=0; j<NC; j++)
576 tab[i].name[j] = np[j];
577yes:
578 return(i);
579}
580
581strip()
582{
583 int i, j, c;
584
585 j = enter("**junk**");
586 for (i = 0; i<size; i++) {
587 if (tab[i].name[0] && tab[i].count<=thres) {
588 printf("%.14s--", tab[i].name);
589 if ((c=getchar())=='y') {
590 tab[i].name[0] = '\0';
591 tab[j].count += tab[i].count;
592 tab[j].realt += tab[i].realt;
593 tab[j].cput += tab[i].cput;
594 tab[j].syst += tab[i].syst;
595 }
596 while (c && c!='\n')
597 c = getchar();
598 }
599 }
600}
601
602time_t
603expand(t)
604unsigned t;
605{
606 register time_t nt;
607
608 nt = t&017777;
609 t >>= 13;
610 while (t!=0) {
611 t--;
612 nt <<= 3;
613 }
614 return(nt);
615}
616
617#include <utmp.h>
618#include <pwd.h>
619
620struct utmp utmp;
621#define NMAX sizeof (utmp.ut_name)
622#define NUID 2048
623
624char names[NUID][NMAX+1];
625
626char *
627getname(uid)
628{
629 register struct passwd *pw;
630 static init;
631 struct passwd *getpwent();
632
633 if (names[uid][0])
634 return (&names[uid][0]);
635 if (init == 2)
636 return (0);
637 if (init == 0)
638 setpwent(), init = 1;
639 while (pw = getpwent()) {
640 if (pw->pw_uid >= NUID)
641 continue;
642 if (names[pw->pw_uid][0])
643 continue;
644 strncpy(names[pw->pw_uid], pw->pw_name, NMAX);
645 if (pw->pw_uid == uid)
646 return (&names[uid][0]);
647 }
648 init = 2;
649 endpwent();
650 return (0);
651}