1: /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/sh.time.c,v 3.0 1991/07/04 21:49:28 christos Exp $ */ 2: /* 3: * sh.time.c: Shell time keeping and printing. 4: */ 5: /*- 6: * Copyright (c) 1980, 1991 The Regents of the University of California. 7: * All rights reserved. 8: * 9: * Redistribution and use in source and binary forms, with or without 10: * modification, are permitted provided that the following conditions 11: * are met: 12: * 1. Redistributions of source code must retain the above copyright 13: * notice, this list of conditions and the following disclaimer. 14: * 2. Redistributions in binary form must reproduce the above copyright 15: * notice, this list of conditions and the following disclaimer in the 16: * documentation and/or other materials provided with the distribution. 17: * 3. All advertising materials mentioning features or use of this software 18: * must display the following acknowledgement: 19: * This product includes software developed by the University of 20: * California, Berkeley and its contributors. 21: * 4. Neither the name of the University nor the names of its contributors 22: * may be used to endorse or promote products derived from this software 23: * without specific prior written permission. 24: * 25: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35: * SUCH DAMAGE. 36: */ 37: #include "config.h" 38: #if !defined(lint) && !defined(pdp11) 39: static char *rcsid() 40: { return "$Id: sh.time.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } 41: #endif 42: 43: #include "sh.h" 44: #if defined(sun) && ! defined(MACH) 45: # include <machine/param.h> 46: #endif /* sun */ 47: 48: /* 49: * C Shell - routines handling process timing and niceing 50: */ 51: #ifdef BSDTIMES 52: # ifndef RUSAGE_SELF 53: # define RUSAGE_SELF 0 54: # define RUSAGE_CHILDREN -1 55: # endif /* RUSAGE_SELF */ 56: #else /* BSDTIMES */ 57: struct tms times0; 58: 59: #endif /* BSDTIMES */ 60: 61: #if !defined(BSDTIMES) && !defined(_SEQUENT_) 62: #ifdef POSIX 63: static void pdtimet __P((clock_t, clock_t)); 64: #else /* POSIX */ 65: static void pdtimet __P((time_t, time_t)); 66: #endif /* POSIX */ 67: #else 68: static void pdeltat __P((tmval_t *, tmval_t *)); 69: #endif 70: 71: void 72: settimes() 73: { 74: #ifdef BSDTIMES 75: struct rusage ruch; 76: 77: (void) gettimeofday(&time0, NULL); 78: (void) getrusage(RUSAGE_SELF, &ru0); 79: (void) getrusage(RUSAGE_CHILDREN, &ruch); 80: ruadd(&ru0, &ruch); 81: #else 82: # ifdef _SEQUENT_ 83: struct pro_stats ruch; 84: 85: (void) get_pro_stats(&time0, PS_SELF, &ru0, &ruch); 86: ruadd(&ru0, &ruch); 87: # else /* _SEQUENT_ */ 88: time0 = times(×0); 89: times0.tms_stime += times0.tms_cstime; 90: times0.tms_utime += times0.tms_cutime; 91: times0.tms_cstime = 0; 92: times0.tms_cutime = 0; 93: # endif /* _SEQUENT_ */ 94: #endif /* BSDTIMES */ 95: } 96: 97: /* 98: * dotime is only called if it is truly a builtin function and not a 99: * prefix to another command 100: */ 101: void 102: dotime() 103: { 104: #ifdef BSDTIMES 105: tmval_t timedol; 106: struct rusage ru1, ruch; 107: 108: (void) getrusage(RUSAGE_SELF, &ru1); 109: (void) getrusage(RUSAGE_CHILDREN, &ruch); 110: ruadd(&ru1, &ruch); 111: (void) gettimeofday(&timedol, NULL); 112: prusage(&ru0, &ru1, &timedol, &time0); 113: #else 114: # ifdef _SEQUENT_ 115: tmval_t timedol; 116: struct pro_stats ru1, ruch; 117: 118: (void) get_pro_stats(&timedol, PS_SELF, &ru1, &ruch); 119: ruadd(&ru1, &ruch); 120: prusage(&ru0, &ru1, &timedol, &time0); 121: # else /* _SEQUENT_ */ 122: # ifndef POSIX 123: time_t timedol; 124: # else /* POSIX */ 125: clock_t timedol; 126: # endif /* POSIX */ 127: 128: struct tms times_dol; 129: 130: timedol = times(×_dol); 131: times_dol.tms_stime += times_dol.tms_cstime; 132: times_dol.tms_utime += times_dol.tms_cutime; 133: times_dol.tms_cstime = 0; 134: times_dol.tms_cutime = 0; 135: prusage(×0, ×_dol, timedol, time0); 136: # endif /* _SEQUENT_ */ 137: #endif /* BSDTIMES */ 138: } 139: 140: /* 141: * donice is only called when it on the line by itself or with a +- value 142: */ 143: void 144: donice(v) 145: register Char **v; 146: { 147: register Char *cp; 148: int nval = 0; 149: 150: v++, cp = *v++; 151: if (cp == 0) 152: nval = 4; 153: else if (*v == 0 && any("+-", cp[0])) 154: nval = getn(cp); 155: #ifdef BSDNICE 156: (void) setpriority(PRIO_PROCESS, 0, nval); 157: #else /* BSDNICE */ 158: (void) nice(nval); 159: #endif /* BSDNICE */ 160: } 161: 162: #ifdef BSDTIMES 163: void 164: ruadd(ru, ru2) 165: register struct rusage *ru, *ru2; 166: { 167: tvadd(&ru->ru_utime, &ru2->ru_utime); 168: tvadd(&ru->ru_stime, &ru2->ru_stime); 169: if (ru2->ru_maxrss > ru->ru_maxrss) 170: ru->ru_maxrss = ru2->ru_maxrss; 171: 172: ru->ru_ixrss += ru2->ru_ixrss; 173: ru->ru_idrss += ru2->ru_idrss; 174: ru->ru_isrss += ru2->ru_isrss; 175: ru->ru_minflt += ru2->ru_minflt; 176: ru->ru_majflt += ru2->ru_majflt; 177: ru->ru_nswap += ru2->ru_nswap; 178: ru->ru_inblock += ru2->ru_inblock; 179: ru->ru_oublock += ru2->ru_oublock; 180: ru->ru_msgsnd += ru2->ru_msgsnd; 181: ru->ru_msgrcv += ru2->ru_msgrcv; 182: ru->ru_nsignals += ru2->ru_nsignals; 183: ru->ru_nvcsw += ru2->ru_nvcsw; 184: ru->ru_nivcsw += ru2->ru_nivcsw; 185: } 186: 187: #else /* BSDTIMES */ 188: # ifdef _SEQUENT_ 189: void 190: ruadd(ru, ru2) 191: register struct pro_stats *ru, *ru2; 192: { 193: tvadd(&ru->ps_utime, &ru2->ps_utime); 194: tvadd(&ru->ps_stime, &ru2->ps_stime); 195: if (ru2->ps_maxrss > ru->ps_maxrss) 196: ru->ps_maxrss = ru2->ps_maxrss; 197: 198: ru->ps_pagein += ru2->ps_pagein; 199: ru->ps_reclaim += ru2->ps_reclaim; 200: ru->ps_zerofill += ru2->ps_zerofill; 201: ru->ps_pffincr += ru2->ps_pffincr; 202: ru->ps_pffdecr += ru2->ps_pffdecr; 203: ru->ps_swap += ru2->ps_swap; 204: ru->ps_syscall += ru2->ps_syscall; 205: ru->ps_volcsw += ru2->ps_volcsw; 206: ru->ps_involcsw += ru2->ps_involcsw; 207: ru->ps_signal += ru2->ps_signal; 208: ru->ps_lread += ru2->ps_lread; 209: ru->ps_lwrite += ru2->ps_lwrite; 210: ru->ps_bread += ru2->ps_bread; 211: ru->ps_bwrite += ru2->ps_bwrite; 212: ru->ps_phread += ru2->ps_phread; 213: ru->ps_phwrite += ru2->ps_phwrite; 214: } 215: 216: # endif /* _SEQUENT_ */ 217: #endif /* BSDTIMES */ 218: 219: #ifdef BSDTIMES 220: 221: /* 222: * PWP: the LOG1024 and pagetok stuff taken from the top command, 223: * written by William LeFebvre 224: */ 225: /* Log base 2 of 1024 is 10 (2^10 == 1024) */ 226: #define LOG1024 10 227: 228: /* Convert clicks (kernel pages) to kbytes ... */ 229: /* If there is no PGSHIFT defined, assume it is 11 */ 230: /* Is this needed for compatability with some old flavor of 4.2 or 4.1? */ 231: #ifndef PGSHIFT 232: # define pagetok(size) ((size) << 1) 233: #else 234: # if PGSHIFT>10 235: # define pagetok(size) ((size) << (PGSHIFT - LOG1024)) 236: # else 237: # define pagetok(size) ((size) >> (LOG1024 - PGSHIFT)) 238: # endif 239: #endif 240: 241: /* 242: * if any other machines return wierd values in the ru_i* stuff, put 243: * the adjusting macro here: 244: */ 245: #ifdef sun 246: # define IADJUST(i) (pagetok(i)/2) 247: #else /* sun */ 248: # define IADJUST(i) (i) 249: #endif /* sun */ 250: 251: void 252: prusage(r0, r1, e, b) 253: register struct rusage *r0, *r1; 254: tmval_t *e, *b; 255: 256: #else /* BSDTIMES */ 257: # ifdef _SEQUENT_ 258: void 259: prusage(r0, r1, e, b) 260: register struct pro_stats *r0, *r1; 261: tmval_t *e, *b; 262: 263: # else /* _SEQUENT_ */ 264: void 265: prusage(bs, es, e, b) 266: struct tms *bs, *es; 267: 268: # ifndef POSIX 269: time_t e, b; 270: 271: # else /* POSIX */ 272: clock_t e, b; 273: 274: # endif /* POSIX */ 275: # endif /* _SEQUENT_ */ 276: #endif /* BSDTIMES */ 277: { 278: #ifdef BSDTIMES 279: register time_t t = 280: (r1->ru_utime.tv_sec - r0->ru_utime.tv_sec) * 100 + 281: (r1->ru_utime.tv_usec - r0->ru_utime.tv_usec) / 10000 + 282: (r1->ru_stime.tv_sec - r0->ru_stime.tv_sec) * 100 + 283: (r1->ru_stime.tv_usec - r0->ru_stime.tv_usec) / 10000; 284: 285: #else 286: # ifdef _SEQUENT_ 287: register time_t t = 288: (r1->ps_utime.tv_sec - r0->ps_utime.tv_sec) * 100 + 289: (r1->ps_utime.tv_usec - r0->ps_utime.tv_usec) / 10000 + 290: (r1->ps_stime.tv_sec - r0->ps_stime.tv_sec) * 100 + 291: (r1->ps_stime.tv_usec - r0->ps_stime.tv_usec) / 10000; 292: 293: # else /* _SEQUENT_ */ 294: # ifndef POSIX 295: register time_t t = (es->tms_utime - bs->tms_utime + 296: es->tms_stime - bs->tms_stime) * 100 / HZ; 297: 298: # else /* POSIX */ 299: register clock_t t = (es->tms_utime - bs->tms_utime + 300: es->tms_stime - bs->tms_stime) * 100 / CLK_TCK; 301: 302: # endif /* POSIX */ 303: # endif /* _SEQUENT_ */ 304: #endif /* BSDTIMES */ 305: 306: register char *cp; 307: register long i; 308: register struct varent *vp = adrof(STRtime); 309: 310: #ifdef BSDTIMES 311: #ifdef pdp11 312: long ms = 313: #else 314: int ms = 315: #endif 316: (e->tv_sec - b->tv_sec) * 100 + (e->tv_usec - b->tv_usec) / 10000; 317: 318: #ifdef pdp11 319: cp = "%Uu %Ss %E %P %I+%Oio %Vov %Wsw"; 320: #else 321: cp = "%Uu %Ss %E %P %X+%Dk %I+%Oio %Fpf+%Ww"; 322: #endif 323: #else 324: # ifdef _SEQUENT_ 325: int ms = 326: (e->tv_sec - b->tv_sec) * 100 + (e->tv_usec - b->tv_usec) / 10000; 327: 328: cp = "%Uu %Ss %E %P %I+%Oio %Fpf+%Ww"; 329: # else /* _SEQUENT_ */ 330: # ifndef POSIX 331: time_t ms = (e - b) * 100 / HZ; 332: 333: # else /* POSIX */ 334: clock_t ms = (e - b) * 100 / CLK_TCK; 335: 336: # endif /* POSIX */ 337: cp = "%Uu %Ss %E %P"; 338: 339: /* 340: * the tms stuff is not very precise, so we fudge it. 341: * granularity fix: can't be more than 100% 342: * this breaks in multi-processor systems... 343: * maybe I should take it out and let people see more then 100% 344: * utilizations. 345: */ 346: if (ms < t && ms != 0) 347: ms = t; 348: # endif /* _SEQUENT_ */ 349: #endif /* BSDTIMES */ 350: #ifdef TDEBUG 351: xprintf("es->tms_utime %lu bs->tms_utime %lu\n", 352: es->tms_utime, bs->tms_utime); 353: xprintf("es->tms_stime %lu bs->tms_stime %lu\n", 354: es->tms_stime, bs->tms_stime); 355: xprintf("ms %lu e %lu b %lu\n", ms, e, b); 356: xprintf("t %lu\n", t); 357: #endif /* TDEBUG */ 358: 359: if (vp && vp->vec[0] && vp->vec[1]) 360: cp = short2str(vp->vec[1]); 361: for (; *cp; cp++) 362: if (*cp != '%') 363: xputchar(*cp); 364: else if (cp[1]) 365: switch (*++cp) { 366: 367: case 'U': /* user CPU time used */ 368: #ifdef BSDTIMES 369: pdeltat(&r1->ru_utime, &r0->ru_utime); 370: #else 371: # ifdef _SEQUENT_ 372: pdeltat(&r1->ps_utime, &r0->ps_utime); 373: # else /* _SEQUENT_ */ 374: # ifndef POSIX 375: pdtimet(es->tms_utime, bs->tms_utime); 376: # else /* POSIX */ 377: pdtimet(es->tms_utime, bs->tms_utime); 378: # endif /* POSIX */ 379: # endif /* _SEQUENT_ */ 380: #endif /* BSDTIMES */ 381: break; 382: 383: case 'S': /* system CPU time used */ 384: #ifdef BSDTIMES 385: pdeltat(&r1->ru_stime, &r0->ru_stime); 386: #else 387: # ifdef _SEQUENT_ 388: pdeltat(&r1->ps_stime, &r0->ps_stime); 389: # else /* _SEQUENT_ */ 390: # ifndef POSIX 391: pdtimet(es->tms_stime, bs->tms_stime); 392: # else /* POSIX */ 393: pdtimet(es->tms_stime, bs->tms_stime); 394: # endif /* POSIX */ 395: # endif /* _SEQUENT_ */ 396: #endif /* BSDTIMES */ 397: break; 398: 399: case 'E': /* elapsed (wall-clock) time */ 400: #ifdef BSDTIMES 401: pcsecs((long) ms); 402: #else /* BSDTIMES */ 403: pcsecs(ms); 404: #endif /* BSDTIMES */ 405: break; 406: 407: case 'P': /* percent time spent running */ 408: /* check if the process did not run */ 409: i = (ms == 0) ? 0 : (t * 1000 / ms); 410: xprintf("%ld.%01ld%%", i / 10, i % 10); /* nn.n% */ 411: break; 412: 413: #ifdef BSDTIMES 414: #ifdef pdp11 415: case 'V': 416: xprintf("%ld", r1->ru_ovly - r0->ru_ovly); 417: break; 418: #endif 419: 420: case 'W': /* number of swaps */ 421: i = r1->ru_nswap - r0->ru_nswap; 422: xprintf("%ld", i); 423: break; 424: 425: case 'X': /* (average) shared text size */ 426: xprintf("%ld", t == 0 ? 0L : 427: IADJUST(r1->ru_ixrss - r0->ru_ixrss) / t); 428: break; 429: 430: case 'D': /* (average) unshared data size */ 431: xprintf("%ld", t == 0 ? 0L : 432: IADJUST(r1->ru_idrss + r1->ru_isrss - 433: (r0->ru_idrss + r0->ru_isrss)) / t); 434: break; 435: 436: case 'K': /* (average) total data memory used */ 437: xprintf("%ld", t == 0 ? 0L : 438: IADJUST((r1->ru_ixrss + r1->ru_isrss + r1->ru_idrss) - 439: (r0->ru_ixrss + r0->ru_idrss + r0->ru_isrss)) / t); 440: break; 441: 442: case 'M': /* max. Resident Set Size */ 443: #ifdef sun 444: /* xprintf("%ld", r1->ru_maxrss * 1024L/(long) getpagesize()); */ 445: xprintf("%ld", pagetok(r1->ru_maxrss)); 446: #else 447: xprintf("%ld", r1->ru_maxrss / 2L); 448: #endif /* sun */ 449: break; 450: 451: case 'F': /* page faults */ 452: xprintf("%ld", r1->ru_majflt - r0->ru_majflt); 453: break; 454: 455: case 'R': /* page reclaims */ 456: xprintf("%ld", r1->ru_minflt - r0->ru_minflt); 457: break; 458: 459: case 'I': /* FS blocks in */ 460: xprintf("%ld", r1->ru_inblock - r0->ru_inblock); 461: break; 462: 463: case 'O': /* FS blocks out */ 464: xprintf("%ld", r1->ru_oublock - r0->ru_oublock); 465: break; 466: 467: case 'r': /* PWP: socket messages recieved */ 468: xprintf("%ld", r1->ru_msgrcv - r0->ru_msgrcv); 469: break; 470: 471: case 's': /* PWP: socket messages sent */ 472: xprintf("%ld", r1->ru_msgsnd - r0->ru_msgsnd); 473: break; 474: 475: case 'k': /* PWP: number of signals recieved */ 476: xprintf("%ld", r1->ru_nsignals - r0->ru_nsignals); 477: break; 478: 479: case 'w': /* PWP: num. voluntary context switches (waits) */ 480: xprintf("%ld", r1->ru_nvcsw - r0->ru_nvcsw); 481: break; 482: 483: case 'c': /* PWP: num. involuntary context switches */ 484: xprintf("%ld", r1->ru_nivcsw - r0->ru_nivcsw); 485: break; 486: #else /* BSDTIMES */ 487: # ifdef _SEQUENT_ 488: case 'W': /* number of swaps */ 489: i = r1->ps_swap - r0->ps_swap; 490: xprintf("%ld", i); 491: break; 492: 493: case 'M': 494: xprintf("%ld", r1->ps_maxrss / 2); 495: break; 496: 497: case 'F': 498: xprintf("%ld", r1->ps_pagein - r0->ps_pagein); 499: break; 500: 501: case 'R': 502: xprintf("%ld", r1->ps_reclaim - r0->ps_reclaim); 503: break; 504: 505: case 'I': 506: xprintf("%ld", r1->ps_bread - r0->ps_bread); 507: break; 508: 509: case 'O': 510: xprintf("%ld", r1->ps_bwrite - r0->ps_bwrite); 511: break; 512: 513: case 'k': 514: xprintf("%ld", r1->ps_signal - r0->ps_signal); 515: break; 516: 517: case 'w': 518: xprintf("%ld", r1->ps_volcsw - r0->ps_volcsw); 519: break; 520: 521: case 'c': 522: xprintf("%ld", r1->ps_involcsw - r0->ps_involcsw); 523: break; 524: 525: case 'Z': 526: xprintf("%ld", r1->ps_zerofill - r0->ps_zerofill); 527: break; 528: 529: case 'i': 530: xprintf("%ld", r1->ps_pffincr - r0->ps_pffincr); 531: break; 532: 533: case 'd': 534: xprintf("%ld", r1->ps_pffdecr - r0->ps_pffdecr); 535: break; 536: 537: case 'Y': 538: xprintf("%ld", r1->ps_syscall - r0->ps_syscall); 539: break; 540: 541: case 'l': 542: xprintf("%ld", r1->ps_lread - r0->ps_lread); 543: break; 544: 545: case 'm': 546: xprintf("%ld", r1->ps_lwrite - r0->ps_lwrite); 547: break; 548: 549: case 'p': 550: xprintf("%ld", r1->ps_phread - r0->ps_phread); 551: break; 552: 553: case 'q': 554: xprintf("%ld", r1->ps_phwrite - r0->ps_phwrite); 555: break; 556: # endif /* _SEQUENT_ */ 557: #endif /* BSDTIMES */ 558: } 559: xputchar('\n'); 560: } 561: 562: #if defined(BSDTIMES) || defined(_SEQUENT_) 563: static void 564: pdeltat(t1, t0) 565: tmval_t *t1, *t0; 566: { 567: tmval_t td; 568: 569: tvsub(&td, t1, t0); 570: xprintf("%d.%01d", td.tv_sec, td.tv_usec / 100000); 571: } 572: 573: void 574: tvadd(tsum, t0) 575: tmval_t *tsum, *t0; 576: { 577: 578: tsum->tv_sec += t0->tv_sec; 579: tsum->tv_usec += t0->tv_usec; 580: if (tsum->tv_usec > 1000000) 581: tsum->tv_sec++, tsum->tv_usec -= 1000000; 582: } 583: 584: void 585: tvsub(tdiff, t1, t0) 586: tmval_t *tdiff, *t1, *t0; 587: { 588: 589: tdiff->tv_sec = t1->tv_sec - t0->tv_sec; 590: tdiff->tv_usec = t1->tv_usec - t0->tv_usec; 591: if (tdiff->tv_usec < 0) 592: tdiff->tv_sec--, tdiff->tv_usec += 1000000; 593: } 594: 595: #else /* !BSDTIMES && !_SEQUENT_ */ 596: static void 597: pdtimet(eval, bval) 598: #ifndef POSIX 599: time_t eval, bval; 600: 601: #else /* POSIX */ 602: clock_t eval, bval; 603: 604: #endif /* POSIX */ 605: { 606: #ifndef POSIX 607: time_t val; 608: 609: #else /* POSIX */ 610: clock_t val; 611: 612: #endif /* POSIX */ 613: 614: #ifndef POSIX 615: val = (eval - bval) * 100 / HZ; 616: #else /* POSIX */ 617: val = (eval - bval) * 100 / CLK_TCK; 618: #endif /* POSIX */ 619: 620: xprintf("%ld.%02ld", val / 100, val - (val / 100 * 100)); 621: } 622: 623: #endif /* BSDTIMES || _SEQUENT_ */