|
|
1.1 ! root 1: #ifndef lint ! 2: static char *sccsid = "@(#)sa.c 4.4 (Berkeley) 83/08/11"; ! 3: #endif ! 4: ! 5: /* ! 6: * Extensive modifications to internal data structures ! 7: * to allow arbitrary number of different commands and users added. ! 8: * ! 9: * Also allowed the digit option on the -v flag (interactive ! 10: * threshold compress) to be a digit string, so one can ! 11: * set the threshold > 9. ! 12: * ! 13: * Also added the -f flag, to force no interactive threshold ! 14: * compression with the -v flag. ! 15: * ! 16: * Robert Henry ! 17: * UC Berkeley ! 18: * 31jan81 ! 19: */ ! 20: #include <stdio.h> ! 21: #include <sys/types.h> ! 22: #include <sys/acct.h> ! 23: #include <signal.h> ! 24: #include <utmp.h> ! 25: #include <pwd.h> ! 26: ! 27: /* interpret command time accounting */ ! 28: ! 29: #define NC sizeof(acctbuf.ac_comm) ! 30: ! 31: struct acct acctbuf; ! 32: int lflg; ! 33: int cflg; ! 34: int Dflg; ! 35: int dflg; ! 36: int iflg; ! 37: int jflg; ! 38: int Kflg; ! 39: int kflg; ! 40: int nflg; ! 41: int aflg; ! 42: int rflg; ! 43: int oflg; ! 44: int tflg; ! 45: int vflg; ! 46: int fflg; ! 47: int uflg; ! 48: int thres; ! 49: int sflg; ! 50: int bflg; ! 51: int mflg; ! 52: ! 53: struct utmp utmp; ! 54: #define NAMELG (sizeof(utmp.ut_name)+1) ! 55: ! 56: struct Olduser{ ! 57: int Us_cnt; ! 58: double Us_ctime; ! 59: double Us_io; ! 60: double Us_imem; ! 61: }; ! 62: ! 63: struct user { ! 64: char name[NC]; /* this is <\001><user id><\000> */ ! 65: struct Olduser oldu; ! 66: char us_name[NAMELG]; ! 67: }; ! 68: #define us_cnt oldu.Us_cnt ! 69: #define us_ctime oldu.Us_ctime ! 70: #define us_io oldu.Us_io ! 71: #define us_imem oldu.Us_imem ! 72: ! 73: /* ! 74: * We protect ourselves from preposterous user id's by looking ! 75: * through the passwd file for the highest uid allocated, and ! 76: * then adding 10 to that. ! 77: * This prevents the user structure from growing too large. ! 78: */ ! 79: #define USERSLOP 10 ! 80: int maxuser; /* highest uid from /etc/passwd, + 10 for slop*/ ! 81: ! 82: struct process { ! 83: char name[NC]; ! 84: int count; ! 85: double realt; ! 86: double cput; ! 87: double syst; ! 88: double imem; ! 89: double io; ! 90: }; ! 91: ! 92: union Tab{ ! 93: struct process p; ! 94: struct user u; ! 95: }; ! 96: ! 97: typedef union Tab cell; ! 98: ! 99: int (*cmp)(); /* compares 2 cells; set to appropriate func */ ! 100: cell *enter(); ! 101: struct user *finduser(); ! 102: struct user *wasuser(); ! 103: ! 104: /* ! 105: * Table elements are keyed by the name of the file exec'ed. ! 106: * Because on large systems, many files can be exec'ed, ! 107: * a static table size may grow to be too large. ! 108: * ! 109: * Table elements are allocated in chunks dynamically, linked ! 110: * together so that they may be retrieved sequentially. ! 111: * ! 112: * An index into the table structure is provided by hashing through ! 113: * a seperate hash table. ! 114: * The hash table is segmented, and dynamically extendable. ! 115: * Realize that the hash table and accounting information is kept ! 116: * in different segments! ! 117: * ! 118: * We have a linked list of hash table segments; within each ! 119: * segment we use a quadratic rehash that touches no more than 1/2 ! 120: * of the buckets in the hash table when probing. ! 121: * If the probe does not find the desired symbol, it moves to the ! 122: * next segment, or allocates a new segment. ! 123: * ! 124: * Hash table segments are kept on the linked list with the first ! 125: * segment always first (that will probably contain the ! 126: * most frequently executed commands) and ! 127: * the last added segment immediately after the first segment, ! 128: * to hopefully gain something by locality of reference. ! 129: * ! 130: * We store the per user information in the same structure as ! 131: * the per exec'ed file information. This allows us to use the ! 132: * same managers for both, as the number of user id's may be very ! 133: * large. ! 134: * User information is keyed by the first character in the name ! 135: * being a '\001', followed by four bytes of (long extended) ! 136: * user id number, followed by a null byte. ! 137: * The actual user names are kept in a seperate field of the ! 138: * user structure, and is filled in upon demand later. ! 139: * Iteration through all users by low user id to high user id ! 140: * is done by just probing the table, which is gross. ! 141: */ ! 142: #define USERKEY '\001' ! 143: #define ISPROCESS(tp) (tp->p.name[0] && (tp->p.name[0] != USERKEY)) ! 144: #define ISUSER(tp) (tp->p.name[0] && (tp->p.name[0] == USERKEY)) ! 145: ! 146: #define TABDALLOP 500 ! 147: struct allocbox{ ! 148: struct allocbox *nextalloc; ! 149: cell tabslots[TABDALLOP]; ! 150: }; ! 151: ! 152: struct allocbox *allochead; /*head of chunk list*/ ! 153: struct allocbox *alloctail; /*tail*/ ! 154: struct allocbox *newbox; /*for creating a new chunk*/ ! 155: cell *nexttab; /*next table element that is free*/ ! 156: int tabsleft; /*slots left in current chunk*/ ! 157: int ntabs; ! 158: /* ! 159: * Iterate through all symbols in the symbol table in declaration ! 160: * order. ! 161: * struct allocbox *allocwalk; ! 162: * cell *sp, *ub; ! 163: * ! 164: * sp points to the desired item, allocwalk and ub are there ! 165: * to make the iteration go. ! 166: */ ! 167: ! 168: #define DECLITERATE(allocwalk, walkpointer, ubpointer) \ ! 169: for(allocwalk = allochead; \ ! 170: allocwalk != 0; \ ! 171: allocwalk = allocwalk->nextalloc) \ ! 172: for (walkpointer = &allocwalk->tabslots[0],\ ! 173: ubpointer = &allocwalk->tabslots[TABDALLOP], \ ! 174: ubpointer = ubpointer > ( (cell *)alloctail) \ ! 175: ? nexttab : ubpointer ;\ ! 176: walkpointer < ubpointer; \ ! 177: walkpointer++ ) ! 178: ! 179: #define TABCHUNKS(allocwalk, tabptr, size) \ ! 180: for (allocwalk = allochead; \ ! 181: allocwalk != 0; \ ! 182: allocwalk = allocwalk->nextalloc) \ ! 183: if ( \ ! 184: (tabptr = &allocwalk->tabslots[0]), \ ! 185: (size = \ ! 186: ( (&allocwalk->tabslots[TABDALLOP]) \ ! 187: > ((cell *)alloctail) \ ! 188: ) \ ! 189: ? (nexttab - tabptr) : TABDALLOP \ ! 190: ), \ ! 191: 1 \ ! 192: ) ! 193: #define PROCESSITERATE(allocwalk, walkpointer, ubpointer) \ ! 194: DECLITERATE(allocwalk, walkpointer, ubpointer) \ ! 195: if (ISPROCESS(walkpointer)) ! 196: ! 197: #define USERITERATE(allocwalk, walkpointer, ubpointer) \ ! 198: DECLITERATE(allocwalk, walkpointer, ubpointer) \ ! 199: if (ISUSER(walkpointer)) ! 200: /* ! 201: * When we have to sort the segmented accounting table, we ! 202: * create a vector of sorted queues that is merged ! 203: * to sort the entire accounting table. ! 204: */ ! 205: struct chunkdesc { ! 206: cell *chunk_tp; ! 207: int chunk_n; ! 208: }; ! 209: ! 210: /* ! 211: * Hash table segments and manager ! 212: */ ! 213: #define NHASH 1103 ! 214: struct hashdallop { ! 215: int h_nused; ! 216: struct hashdallop *h_next; ! 217: cell *h_tab[NHASH]; ! 218: }; ! 219: struct hashdallop *htab; /* head of the list */ ! 220: int htabinstall; /* install the symbol */ ! 221: ! 222: double treal; ! 223: double tcpu; ! 224: double tsys; ! 225: double tio; ! 226: double timem; ! 227: cell *junkp; ! 228: char *sname; ! 229: double ncom; ! 230: time_t expand(); ! 231: char *getname(); ! 232: ! 233: /* ! 234: * usracct saves records of type Olduser. ! 235: * There is one record for every possible uid less than ! 236: * the largest uid seen in the previous usracct or in savacct. ! 237: * uid's that had no activity correspond to zero filled slots; ! 238: * thus one can index the file and get the user record out. ! 239: * It would be better to save only user information for users ! 240: * that the system knows about to save space, but that is not ! 241: * upward compatabile with the old system. ! 242: * ! 243: * In the old version of sa, uid's greater than 999 were not handled ! 244: * properly; this system will do that. ! 245: */ ! 246: ! 247: #ifdef DEBUG ! 248: #define USRACCT "./usracct" ! 249: #define SAVACCT "./savacct" ! 250: #define ACCT "./acct" ! 251: #else ! 252: #define USRACCT "/usr/adm/usracct" ! 253: #define SAVACCT "/usr/adm/savacct" ! 254: #define ACCT "/usr/adm/acct" ! 255: #endif DEBUG ! 256: ! 257: ! 258: int cellcmp(); ! 259: cell *junkp = 0; ! 260: /* ! 261: * The threshold is built up from digits in the argv ; ! 262: * eg, -v1s0u1 ! 263: * will build a value of thres of 101. ! 264: * ! 265: * If the threshold is zero after processing argv, it is set to 1 ! 266: */ ! 267: int thres = 0; ! 268: int htabinstall = 1; ! 269: int maxuser = -1; ! 270: int (*cmp)(); ! 271: ! 272: extern tcmp(), ncmp(), bcmp(), dcmp(), Dcmp(), kcmp(), Kcmp(); ! 273: extern double sum(); ! 274: ! 275: main(argc, argv) ! 276: char **argv; ! 277: { ! 278: FILE *ff; ! 279: double ft; ! 280: register struct allocbox *allocwalk; ! 281: register cell *tp, *ub; ! 282: int i, j, size, nchunks, smallest; ! 283: struct chunkdesc *chunkvector; ! 284: ! 285: maxuser = USERSLOP + getmaxuid(); ! 286: ! 287: tabinit(); ! 288: cmp = tcmp; ! 289: if (argc>1) ! 290: if (argv[1][0]=='-') { ! 291: argv++; ! 292: argc--; ! 293: for(i=1; argv[0][i]; i++) ! 294: switch(argv[0][i]) { ! 295: ! 296: case 'o': ! 297: oflg++; ! 298: break; ! 299: ! 300: case 'i': ! 301: iflg++; ! 302: break; ! 303: ! 304: case 'b': ! 305: bflg++; ! 306: cmp = bcmp; ! 307: break; ! 308: ! 309: case 'l': ! 310: lflg++; ! 311: break; ! 312: ! 313: case 'c': ! 314: cflg++; ! 315: break; ! 316: ! 317: case 'd': ! 318: dflg++; ! 319: cmp = dcmp; ! 320: break; ! 321: ! 322: case 'D': ! 323: Dflg++; ! 324: cmp = Dcmp; ! 325: break; ! 326: ! 327: case 'j': ! 328: jflg++; ! 329: break; ! 330: ! 331: case 'k': ! 332: kflg++; ! 333: cmp = kcmp; ! 334: break; ! 335: ! 336: case 'K': ! 337: Kflg++; ! 338: cmp = Kcmp; ! 339: break; ! 340: ! 341: case 'n': ! 342: nflg++; ! 343: cmp = ncmp; ! 344: break; ! 345: ! 346: case 'a': ! 347: aflg++; ! 348: break; ! 349: ! 350: case 'r': ! 351: rflg++; ! 352: break; ! 353: ! 354: case 't': ! 355: tflg++; ! 356: break; ! 357: ! 358: case 's': ! 359: sflg++; ! 360: aflg++; ! 361: break; ! 362: ! 363: case '0': ! 364: case '1': ! 365: case '2': ! 366: case '3': ! 367: case '4': ! 368: case '5': ! 369: case '6': ! 370: case '7': ! 371: case '8': ! 372: case '9': ! 373: thres = thres * 10 + (argv[0][i]-'0'); ! 374: break; ! 375: ! 376: case 'v': ! 377: vflg++; ! 378: break; ! 379: ! 380: case 'f': ! 381: fflg++; /* force v option; no tty interaction */ ! 382: break; ! 383: ! 384: case 'u': ! 385: uflg++; ! 386: break; ! 387: ! 388: case 'm': ! 389: mflg++; ! 390: break; ! 391: } ! 392: } ! 393: if (thres == 0) ! 394: thres = 1; ! 395: if (iflg==0) ! 396: init(); ! 397: if (argc<2) ! 398: doacct(ACCT); ! 399: else while (--argc) ! 400: doacct(*++argv); ! 401: if (uflg) { ! 402: return; ! 403: } ! 404: ! 405: /* ! 406: * cleanup pass ! 407: * put junk together ! 408: */ ! 409: ! 410: if (vflg) ! 411: strip(); ! 412: if(!aflg) ! 413: PROCESSITERATE(allocwalk, tp, ub){ ! 414: for(j=0; j<NC; j++) ! 415: if(tp->p.name[j] == '?') ! 416: goto yes; ! 417: if(tp->p.count != 1) ! 418: continue; ! 419: yes: ! 420: if(junkp == 0) ! 421: junkp = enter("***other"); ! 422: junkp->p.count += tp->p.count; ! 423: junkp->p.realt += tp->p.realt; ! 424: junkp->p.cput += tp->p.cput; ! 425: junkp->p.syst += tp->p.syst; ! 426: junkp->p.imem += tp->p.imem; ! 427: junkp->p.io += tp->p.io; ! 428: tp->p.name[0] = 0; ! 429: } ! 430: if (sflg) { ! 431: signal(SIGINT, SIG_IGN); ! 432: if ((ff = fopen(USRACCT, "w")) != NULL) { ! 433: static struct user ZeroUser = {0}; ! 434: struct user *up; ! 435: int uid; ! 436: /* ! 437: * Write out just enough user slots, ! 438: * filling with zero slots for users that ! 439: * weren't found. ! 440: * The file can be indexed directly by uid ! 441: * to get the correct record. ! 442: */ ! 443: for (uid = 0; uid < maxuser; uid++){ ! 444: if ( (up = wasuser(uid)) != 0) ! 445: fwrite((char *)&(up->oldu), ! 446: sizeof(struct Olduser),1,ff); ! 447: else ! 448: fwrite((char *)&(ZeroUser.oldu), ! 449: sizeof(struct Olduser),1,ff); ! 450: } ! 451: } ! 452: if ((ff = fopen(SAVACCT, "w")) == NULL) { ! 453: printf("Can't save\n"); ! 454: exit(0); ! 455: } ! 456: PROCESSITERATE(allocwalk, tp, ub) ! 457: fwrite((char *)&(tp->p), sizeof(struct process), 1, ff); ! 458: fclose(ff); ! 459: creat(sname, 0644); ! 460: signal(SIGINT, SIG_DFL); ! 461: } ! 462: /* ! 463: * sort and print ! 464: */ ! 465: if (mflg) { ! 466: printmoney(); ! 467: exit(0); ! 468: } ! 469: column(ncom, treal, tcpu, tsys, timem, tio); ! 470: printf("\n"); ! 471: ! 472: /* ! 473: * the fragmented table is sorted by sorting each fragment ! 474: * and then merging. ! 475: */ ! 476: nchunks = 0; ! 477: TABCHUNKS(allocwalk, tp, size){ ! 478: qsort(tp, size, sizeof(cell), cellcmp); ! 479: nchunks ++; ! 480: } ! 481: chunkvector = (struct chunkdesc *)calloc(nchunks, ! 482: sizeof(struct chunkdesc)); ! 483: nchunks = 0; ! 484: TABCHUNKS(allocwalk, tp, size){ ! 485: chunkvector[nchunks].chunk_tp = tp; ! 486: chunkvector[nchunks].chunk_n = size; ! 487: nchunks++; ! 488: } ! 489: for(; nchunks; ){ ! 490: /* ! 491: * Find the smallest element at the head of the queues. ! 492: */ ! 493: smallest = 0; ! 494: for (i = 1; i < nchunks; i++){ ! 495: if (cellcmp(chunkvector[i].chunk_tp, ! 496: chunkvector[smallest].chunk_tp) < 0) ! 497: smallest = i; ! 498: } ! 499: tp = chunkvector[smallest].chunk_tp++; ! 500: /* ! 501: * If this queue is drained, drop the chunk count, ! 502: * and readjust the queues. ! 503: */ ! 504: if (--chunkvector[smallest].chunk_n == 0){ ! 505: nchunks--; ! 506: for (i = smallest; i < nchunks; i++) ! 507: chunkvector[i] = chunkvector[i+1]; ! 508: } ! 509: if (ISPROCESS(tp)){ ! 510: ft = tp->p.count; ! 511: column(ft, tp->p.realt, tp->p.cput, ! 512: tp->p.syst, tp->p.imem, tp->p.io); ! 513: printf(" %.14s\n", tp->p.name); ! 514: } ! 515: } /* iterate to merge the lists */ ! 516: } ! 517: ! 518: printmoney() ! 519: { ! 520: register i; ! 521: register char *cp; ! 522: register struct user *up; ! 523: ! 524: getnames(); /* fetches all of the names! */ ! 525: for (i = 0; i < maxuser; i++) { ! 526: if ( (up = wasuser(i)) != 0){ ! 527: if (up->us_cnt) { ! 528: if (up->us_name[0]) ! 529: printf("%-8s", up->us_name); ! 530: else ! 531: printf("%-8d", i); ! 532: printf("%7u %9.2fcpu %10.0ftio %12.0fk*sec\n", ! 533: up->us_cnt, up->us_ctime / 60, ! 534: up->us_io, ! 535: up->us_imem / (60 * 2)); ! 536: } ! 537: } ! 538: } ! 539: } ! 540: ! 541: column(n, a, b, c, d, e) ! 542: double n, a, b, c, d, e; ! 543: { ! 544: ! 545: printf("%8.0f", n); ! 546: if(cflg) { ! 547: if(n == ncom) ! 548: printf("%9s", ""); else ! 549: printf("%8.2f%%", 100.*n/ncom); ! 550: } ! 551: col(n, a, treal, "re"); ! 552: if (oflg) ! 553: col(n, 3600*(b/(b+c)), tcpu+tsys, "u/s"); ! 554: else if(lflg) { ! 555: col(n, b, tcpu, "u"); ! 556: col(n, c, tsys, "s"); ! 557: } else ! 558: col(n, b+c, tcpu+tsys, "cp"); ! 559: if(tflg) ! 560: printf("%8.1f", a/(b+c), "re/cp"); ! 561: if(dflg || !Dflg) ! 562: printf("%10.0favio", e/(n?n:1)); ! 563: else ! 564: printf("%10.0ftio", e); ! 565: if (kflg || !Kflg) ! 566: printf("%10.0fk", d/(2*((b+c)!=0.0?(b+c):1.0))); ! 567: else ! 568: printf("%10.0fk*sec", d/(2*60)); ! 569: } ! 570: ! 571: col(n, a, m, cp) ! 572: double n, a, m; ! 573: char *cp; ! 574: { ! 575: ! 576: if(jflg) ! 577: printf("%11.2f%s", a/(n*60.), cp); else ! 578: printf("%11.2f%s", a/3600., cp); ! 579: if(cflg) { ! 580: if(a == m) ! 581: printf("%9s", ""); else ! 582: printf("%8.2f%%", 100.*a/m); ! 583: } ! 584: } ! 585: ! 586: doacct(f) ! 587: char *f; ! 588: { ! 589: FILE *ff; ! 590: long x, y, z; ! 591: struct acct fbuf; ! 592: register char *cp; ! 593: register int c; ! 594: register struct user *up; ! 595: register cell *tp; ! 596: #ifdef DEBUG ! 597: int nrecords = 0; ! 598: #endif DEBUG ! 599: ! 600: if (sflg && sname) { ! 601: printf("Only 1 file with -s\n"); ! 602: exit(0); ! 603: } ! 604: if (sflg) ! 605: sname = f; ! 606: if ((ff = fopen(f, "r"))==NULL) { ! 607: printf("Can't open %s\n", f); ! 608: return; ! 609: } ! 610: while (fread((char *)&fbuf, sizeof(fbuf), 1, ff) == 1) { ! 611: #ifdef DEBUG ! 612: if (++nrecords % 1000 == 0) ! 613: printf("Input record from %s number %d\n", ! 614: f, nrecords); ! 615: #endif DEBUG ! 616: if (fbuf.ac_comm[0]==0) { ! 617: fbuf.ac_comm[0] = '?'; ! 618: } ! 619: for (cp = fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++) { ! 620: c = *cp & 0377; ! 621: if (c && (c < ' ' || c >= 0200)) { ! 622: *cp = '?'; ! 623: } ! 624: } ! 625: if (fbuf.ac_flag&AFORK) { ! 626: for (cp=fbuf.ac_comm; cp < &fbuf.ac_comm[NC]; cp++) ! 627: if (*cp==0) { ! 628: *cp = '*'; ! 629: break; ! 630: } ! 631: } ! 632: x = expand(fbuf.ac_utime) + expand(fbuf.ac_stime); ! 633: y = fbuf.ac_mem; ! 634: z = expand(fbuf.ac_io); ! 635: if (uflg) { ! 636: printf("%3d%6.1fcp %6dmem %6dio %.14s\n", ! 637: fbuf.ac_uid, x, y, z, fbuf.ac_comm); ! 638: continue; ! 639: } ! 640: up = finduser(fbuf.ac_uid); ! 641: if (up == 0) ! 642: continue; /* preposterous user id */ ! 643: up->us_cnt++; ! 644: up->us_ctime += x; ! 645: up->us_imem += x * y; ! 646: up->us_io += z; ! 647: ncom += 1.0; ! 648: ! 649: tp = enter(fbuf.ac_comm); ! 650: tp->p.imem += x * y; ! 651: timem += x * y; ! 652: tp->p.count++; ! 653: x = expand(fbuf.ac_etime); ! 654: tp->p.realt += x; ! 655: treal += x; ! 656: x = expand(fbuf.ac_utime); ! 657: tp->p.cput += x; ! 658: tcpu += x; ! 659: x = expand(fbuf.ac_stime); ! 660: tp->p.syst += x; ! 661: tsys += x; ! 662: tp->p.io += z; ! 663: tio += z; ! 664: } ! 665: fclose(ff); ! 666: } ! 667: ! 668: /* ! 669: * Generalized cell compare routine, to cast out users ! 670: */ ! 671: cellcmp(p1, p2) ! 672: cell *p1, *p2; ! 673: { ! 674: if (ISPROCESS(p1)){ ! 675: if (ISPROCESS(p2)) ! 676: return((*cmp)(p1, p2)); ! 677: return(-1); ! 678: } ! 679: if (ISPROCESS(p2)) ! 680: return(1); ! 681: return(0); ! 682: } ! 683: ! 684: ncmp(p1, p2) ! 685: cell *p1, *p2; ! 686: { ! 687: ! 688: if(p1->p.count == p2->p.count) ! 689: return(tcmp(p1, p2)); ! 690: if(rflg) ! 691: return(p1->p.count - p2->p.count); ! 692: return(p2->p.count - p1->p.count); ! 693: } ! 694: ! 695: bcmp(p1, p2) ! 696: cell *p1, *p2; ! 697: { ! 698: double f1, f2; ! 699: double sum(); ! 700: ! 701: f1 = sum(p1)/p1->p.count; ! 702: f2 = sum(p2)/p2->p.count; ! 703: if(f1 < f2) { ! 704: if(rflg) ! 705: return(-1); ! 706: return(1); ! 707: } ! 708: if(f1 > f2) { ! 709: if(rflg) ! 710: return(1); ! 711: return(-1); ! 712: } ! 713: return(0); ! 714: } ! 715: ! 716: Kcmp(p1, p2) ! 717: cell *p1, *p2; ! 718: { ! 719: ! 720: if (p1->p.imem < p2->p.imem) { ! 721: if(rflg) ! 722: return(-1); ! 723: return(1); ! 724: } ! 725: if (p1->p.imem > p2->p.imem) { ! 726: if(rflg) ! 727: return(1); ! 728: return(-1); ! 729: } ! 730: return(0); ! 731: } ! 732: ! 733: kcmp(p1, p2) ! 734: cell *p1, *p2; ! 735: { ! 736: double a1, a2; ! 737: ! 738: a1 = p1->p.imem / ((p1->p.cput+p1->p.syst)?(p1->p.cput+p1->p.syst):1); ! 739: a2 = p2->p.imem / ((p2->p.cput+p2->p.syst)?(p2->p.cput+p2->p.syst):1); ! 740: if (a1 < a2) { ! 741: if(rflg) ! 742: return(-1); ! 743: return(1); ! 744: } ! 745: if (a1 > a2) { ! 746: if(rflg) ! 747: return(1); ! 748: return(-1); ! 749: } ! 750: return(0); ! 751: } ! 752: ! 753: dcmp(p1, p2) ! 754: cell *p1, *p2; ! 755: { ! 756: double a1, a2; ! 757: ! 758: a1 = p1->p.io / (p1->p.count?p1->p.count:1); ! 759: a2 = p2->p.io / (p2->p.count?p2->p.count:1); ! 760: if (a1 < a2) { ! 761: if(rflg) ! 762: return(-1); ! 763: return(1); ! 764: } ! 765: if (a1 > a2) { ! 766: if(rflg) ! 767: return(1); ! 768: return(-1); ! 769: } ! 770: return(0); ! 771: } ! 772: ! 773: Dcmp(p1, p2) ! 774: cell *p1, *p2; ! 775: { ! 776: ! 777: if (p1->p.io < p2->p.io) { ! 778: if(rflg) ! 779: return(-1); ! 780: return(1); ! 781: } ! 782: if (p1->p.io > p2->p.io) { ! 783: if(rflg) ! 784: return(1); ! 785: return(-1); ! 786: } ! 787: return(0); ! 788: } ! 789: ! 790: tcmp(p1, p2) ! 791: cell *p1, *p2; ! 792: { ! 793: extern double sum(); ! 794: double f1, f2; ! 795: ! 796: f1 = sum(p1); ! 797: f2 = sum(p2); ! 798: if(f1 < f2) { ! 799: if(rflg) ! 800: return(-1); ! 801: return(1); ! 802: } ! 803: if(f1 > f2) { ! 804: if(rflg) ! 805: return(1); ! 806: return(-1); ! 807: } ! 808: return(0); ! 809: } ! 810: ! 811: double sum(p) ! 812: cell *p; ! 813: { ! 814: ! 815: if(p->p.name[0] == 0) ! 816: return(0.0); ! 817: return( p->p.cput + p->p.syst); ! 818: } ! 819: ! 820: init() ! 821: { ! 822: struct user userbuf; ! 823: struct process tbuf; ! 824: register cell *tp; ! 825: register struct user *up; ! 826: int uid; ! 827: FILE *f; ! 828: ! 829: if ((f = fopen(SAVACCT, "r")) == NULL) ! 830: goto gshm; ! 831: while (fread((char *)&tbuf, sizeof(struct process), 1, f) == 1) { ! 832: tp = enter(tbuf.name); ! 833: ncom += tbuf.count; ! 834: tp->p.count = tbuf.count; ! 835: treal += tbuf.realt; ! 836: tp->p.realt = tbuf.realt; ! 837: tcpu += tbuf.cput; ! 838: tp->p.cput = tbuf.cput; ! 839: tsys += tbuf.syst; ! 840: tp->p.syst = tbuf.syst; ! 841: tio += tbuf.io; ! 842: tp->p.io = tbuf.io; ! 843: timem += tbuf.imem; ! 844: tp->p.imem = tbuf.imem; ! 845: } ! 846: fclose(f); ! 847: gshm: ! 848: if ((f = fopen(USRACCT, "r")) == NULL) ! 849: return; ! 850: for(uid = 0; ! 851: fread((char *)&(userbuf.oldu), sizeof(struct Olduser), 1, f) == 1; ! 852: uid++){ ! 853: if (userbuf.us_cnt){ ! 854: up = finduser(uid); ! 855: if (up == 0) ! 856: continue; /* preposterous user id */ ! 857: up->oldu = userbuf.oldu; ! 858: } ! 859: } ! 860: fclose(f); ! 861: } ! 862: ! 863: strip() ! 864: { ! 865: int c; ! 866: register struct allocbox *allocwalk; ! 867: register cell *tp, *ub, *junkp; ! 868: ! 869: if (fflg) ! 870: printf("Categorizing commands used %d times or fewer as **junk**\n", ! 871: thres); ! 872: junkp = enter("**junk**"); ! 873: PROCESSITERATE(allocwalk, tp, ub){ ! 874: if (tp->p.name[0] && tp->p.count <= thres) { ! 875: if (!fflg) ! 876: printf("%.14s--", tp->p.name); ! 877: if (fflg || ((c=getchar())=='y')) { ! 878: tp->p.name[0] = '\0'; ! 879: junkp->p.count += tp->p.count; ! 880: junkp->p.realt += tp->p.realt; ! 881: junkp->p.cput += tp->p.cput; ! 882: junkp->p.syst += tp->p.syst; ! 883: junkp->p.imem += tp->p.imem; ! 884: junkp->p.io += tp->p.io; ! 885: } ! 886: if (!fflg) ! 887: while (c && c!='\n') ! 888: c = getchar(); ! 889: } ! 890: } ! 891: } ! 892: ! 893: time_t ! 894: expand(t) ! 895: unsigned t; ! 896: { ! 897: register time_t nt; ! 898: ! 899: nt = t&017777; ! 900: t >>= 13; ! 901: while (t!=0) { ! 902: t--; ! 903: nt <<= 3; ! 904: } ! 905: return(nt); ! 906: } ! 907: ! 908: static char UserKey[NAMELG + 2]; ! 909: ! 910: char * ! 911: makekey(uid) ! 912: int uid; ! 913: { ! 914: sprintf(UserKey+1, "%04x", uid); ! 915: UserKey[0] = USERKEY; ! 916: return(UserKey); ! 917: } ! 918: ! 919: struct user * ! 920: wasuser(uid) ! 921: int uid; ! 922: { ! 923: struct user *tp; ! 924: ! 925: htabinstall = 0; ! 926: tp = finduser(uid); ! 927: htabinstall = 1; ! 928: return(tp); ! 929: } ! 930: ! 931: /* ! 932: * Only call this if you really want to insert it in the table! ! 933: */ ! 934: struct user * ! 935: finduser(uid) ! 936: int uid; ! 937: { ! 938: ! 939: if (uid > maxuser){ ! 940: fprintf(stderr, "Preposterous user id, %d: ignored\n", uid); ! 941: return(0); ! 942: } ! 943: return((struct user*)enter(makekey(uid))); ! 944: } ! 945: ! 946: /* ! 947: * Set the names of all users in the password file. ! 948: * We will later not print those that didn't do anything. ! 949: */ ! 950: getnames() ! 951: { ! 952: register struct user *tp; ! 953: register struct passwd *pw; ! 954: struct passwd *getpwent(); ! 955: ! 956: setpwent(); ! 957: while (pw = getpwent()){ ! 958: if ( (tp = wasuser(pw->pw_uid)) != 0) ! 959: strncpy(tp->us_name, pw->pw_name, NAMELG); ! 960: } ! 961: endpwent(); ! 962: } ! 963: ! 964: int ! 965: getmaxuid() ! 966: { ! 967: register struct user *tp; ! 968: register struct passwd *pw; ! 969: struct passwd *getpwent(); ! 970: int maxuid = -1; ! 971: ! 972: setpwent(); ! 973: while(pw = getpwent()){ ! 974: if (pw->pw_uid > maxuid) ! 975: maxuid = pw->pw_uid; ! 976: } ! 977: endpwent(); ! 978: return(maxuid); ! 979: } ! 980: ! 981: tabinit() ! 982: { ! 983: allochead = 0; ! 984: alloctail = 0; ! 985: nexttab = 0; ! 986: tabsleft = 0; ! 987: htab = 0; ! 988: ntabs = 0; ! 989: htaballoc(); /* get the first part of the hash table */ ! 990: } ! 991: ! 992: #define ALLOCQTY sizeof (struct allocbox) ! 993: cell * ! 994: taballoc() ! 995: { ! 996: ! 997: if (tabsleft == 0){ ! 998: newbox = (struct allocbox *)calloc(1, ALLOCQTY); ! 999: tabsleft = TABDALLOP; ! 1000: nexttab = &newbox->tabslots[0]; ! 1001: if (alloctail == 0){ ! 1002: allochead = alloctail = newbox; ! 1003: } else { ! 1004: alloctail->nextalloc = newbox; ! 1005: alloctail = newbox; ! 1006: } ! 1007: } ! 1008: --tabsleft; ! 1009: ++ntabs; ! 1010: #ifdef DEBUG ! 1011: if (ntabs % 100 == 0) ! 1012: printf("##Accounting table slot # %d\n", ntabs); ! 1013: #endif DEBUG ! 1014: return(nexttab++); ! 1015: } ! 1016: ! 1017: htaballoc() ! 1018: { ! 1019: register struct hashdallop *new; ! 1020: #ifdef DEBUG ! 1021: static int ntables = 0; ! 1022: ! 1023: printf("%%%New hash table chunk allocated, number %d\n", ++ntables); ! 1024: #endif DEBUG ! 1025: new = (struct hashdallop *)calloc(1, sizeof (struct hashdallop)); ! 1026: if (htab == 0) ! 1027: htab = new; ! 1028: else { /* add AFTER the 1st slot */ ! 1029: new->h_next = htab->h_next; ! 1030: htab->h_next = new; ! 1031: } ! 1032: } ! 1033: ! 1034: #define HASHCLOGGED (NHASH / 2) ! 1035: /* ! 1036: * Lookup a symbol passed in as the argument. ! 1037: * ! 1038: * We take pains to avoid function calls; this function ! 1039: * is called quite frequently, and the calling overhead ! 1040: * contributes significantly to the overall execution speed of sa. ! 1041: */ ! 1042: cell * ! 1043: enter(name) ! 1044: char *name; ! 1045: { ! 1046: static int initialprobe; ! 1047: register cell **hp; ! 1048: register char *from, *to; ! 1049: register int len, nprobes; ! 1050: static struct hashdallop *hdallop, *emptyhd; ! 1051: static cell **emptyslot, **hp_ub; ! 1052: ! 1053: emptyslot = 0; ! 1054: for (nprobes = 0, from = name, len = 0; ! 1055: *from && len < NC; ! 1056: nprobes <<= 2, nprobes += *from++, len++) ! 1057: continue; ! 1058: nprobes += from[-1] << 5; ! 1059: nprobes %= NHASH; ! 1060: if (nprobes < 0) ! 1061: nprobes += NHASH; ! 1062: ! 1063: initialprobe = nprobes; ! 1064: for (hdallop = htab; hdallop != 0; hdallop = hdallop->h_next){ ! 1065: for (hp = &(hdallop->h_tab[initialprobe]), ! 1066: nprobes = 1, ! 1067: hp_ub = &(hdallop->h_tab[NHASH]); ! 1068: (*hp) && (nprobes < NHASH); ! 1069: hp += nprobes, ! 1070: hp -= (hp >= hp_ub) ? NHASH:0, ! 1071: nprobes += 2) ! 1072: { ! 1073: from = name; ! 1074: to = (*hp)->p.name; ! 1075: ! 1076: for (len = 0; (len<NC) && *from; len++) ! 1077: if (*from++ != *to++) ! 1078: goto nextprobe; ! 1079: if (len >= NC) /*both are maximal length*/ ! 1080: return(*hp); ! 1081: if (*to == 0) /*assert *from == 0*/ ! 1082: return(*hp); ! 1083: nextprobe: ; ! 1084: } ! 1085: if (*hp == 0 && emptyslot == 0 && ! 1086: hdallop->h_nused < HASHCLOGGED) { ! 1087: emptyslot = hp; ! 1088: emptyhd = hdallop; ! 1089: } ! 1090: } ! 1091: if (emptyslot == 0) { ! 1092: htaballoc(); ! 1093: hdallop = htab->h_next; /* aren't we smart! */ ! 1094: hp = &hdallop->h_tab[initialprobe]; ! 1095: } else { ! 1096: hdallop = emptyhd; ! 1097: hp = emptyslot; ! 1098: } ! 1099: if (htabinstall){ ! 1100: *hp = taballoc(); ! 1101: hdallop->h_nused++; ! 1102: for(len = 0, from = name, to = (*hp)->p.name; (len<NC); len++) ! 1103: if ((*to++ = *from++) == '\0') ! 1104: break; ! 1105: return(*hp); ! 1106: } ! 1107: return(0); ! 1108: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.