1: /* 2: * Copyright (c) 1980 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #ifndef lint 8: static char sccsid[] = "@(#)pmon.c 5.1 (Berkeley) 6/5/85"; 9: #endif not lint 10: 11: /* 12: * pxp - Pascal execution profiler 13: * 14: * Bill Joy UCB 15: * Version 1.2 January 1979 16: */ 17: 18: #include "0.h" 19: 20: /* 21: * Profile counter processing cluster 22: * 23: * This file contains all routines which do the hard work in profiling. 24: * 25: * The first group of routines (getit, getpmon, getcore, and pmread) 26: * deal with extracting data from the pmon.out and (with more difficulty) 27: * core files. 28: * 29: * The routines cnttab and prttab collect counters for 30: * and print the summary table respectively. 31: * 32: * The routines "*cnt*" deal with manipulation of counters, 33: * especially the "current" counter px. 34: */ 35: STATIC struct pxcnt px; 36: 37: /* 38: * Table to record info 39: * for procedure/function summary 40: */ 41: STATIC struct pftab { 42: long pfcnt; 43: short pfline; 44: char *pfname; 45: short pflev; 46: } *zpf; 47: 48: /* 49: * Global variables 50: */ 51: STATIC long *zbuf; /* Count buffer */ 52: STATIC short zcnt; /* Number of counts */ 53: STATIC short zpfcnt; /* Number of proc/funcs's */ 54: STATIC short gcountr; /* Unique name generator */ 55: STATIC short zfil; /* I/o unit for count data reads */ 56: STATIC short lastpf; /* Total # of procs and funcs for consistency chk */ 57: 58: getit(fp) 59: register char *fp; 60: { 61: 62: if (core) 63: getcore(fp); 64: else 65: getpmon(fp); 66: } 67: 68: /* 69: * Setup monitor data buffer from pmon.out 70: * style file whose name is fp. 71: */ 72: getpmon(fp) 73: char *fp; 74: { 75: register char *cp; 76: short garbage; 77: 78: zfil = open(fp, 0); 79: if (zfil < 0) { 80: perror(fp); 81: pexit(NOSTART); 82: } 83: if (pmread() < 0 || read(zfil, &garbage, 1) == 1) { 84: Perror(fp, "Bad format for pmon.out style file"); 85: exit(1); 86: } 87: close(zfil); 88: return; 89: } 90: 91: STATIC char nospcm[] = "Not enough memory for count buffers\n"; 92: 93: pmnospac() 94: { 95: 96: write(2, nospcm, sizeof nospcm); 97: pexit(NOSTART); 98: } 99: 100: /* 101: * Structure of the first few 102: * items of a px core dump. 103: */ 104: STATIC struct info { 105: char *off; /* Self-reference for pure text */ 106: short type; /* 0 = non-pure text, 1 = pure text */ 107: char *bp; /* Core address of pxps struct */ 108: } inf; 109: 110: /* 111: * First few words of the px 112: * information structure. 113: */ 114: STATIC struct pxps { 115: char *buf; 116: short cnt; 117: } pxp; 118: 119: getcore(fp) 120: char *fp; 121: { 122: 123: write(2, "-c: option not supported\n", sizeof("-c: option not supported\n")); 124: pexit(ERRS); 125: /* 126: short pm; 127: 128: zfil = open(fp, 0); 129: if (zfil < 0) { 130: perror(fp); 131: pexit(NOSTART); 132: } 133: if (lseek(zfil, 02000, 0) < 0) 134: goto format; 135: if (read(zfil, &inf, sizeof inf) < 0) 136: goto format; 137: if (inf.type != 0 && inf.type != 1) 138: goto format; 139: if (inf.type) 140: inf.bp =- inf.off; 141: if (lseek(zfil, inf.bp + 02000, 0) < 0) 142: goto format; 143: if (read(zfil, &pxp, sizeof pxp) != sizeof pxp) 144: goto format; 145: if (pxp.buf == NIL) { 146: Perror(fp, "No profile data in file"); 147: exit(1); 148: } 149: if (inf.type) 150: pxp.buf =- inf.off; 151: if (lseek(zfil, pxp.buf + 02000, 0) < 0) 152: goto format; 153: if (pmread() < 0) 154: goto format; 155: close(zfil); 156: return; 157: format: 158: Perror(fp, "Not a Pascal system core file"); 159: exit(1); 160: */ 161: } 162: 163: pmread() 164: { 165: register i; 166: register char *cp; 167: struct { 168: long no; 169: long tim; 170: long cntrs; 171: long rtns; 172: } zmagic; 173: 174: if (read(zfil, &zmagic, sizeof zmagic) != sizeof zmagic) 175: return (-1); 176: if (zmagic.no != 0426) 177: return (-1); 178: ptvec = zmagic.tim; 179: zcnt = zmagic.cntrs; 180: zpfcnt = zmagic.rtns; 181: cp = zbuf = pcalloc(i = (zcnt + 1) * sizeof *zbuf, 1); 182: if (cp == -1) 183: pmnospac(); 184: cp = zpf = pcalloc(zpfcnt * sizeof *zpf, 1); 185: if (cp == -1) 186: pmnospac(); 187: i -= sizeof(zmagic); 188: if (read(zfil, zbuf + (sizeof(zmagic) / sizeof(*zbuf)), i) != i) 189: return (-1); 190: zbuf++; 191: return (0); 192: } 193: 194: cnttab(s, no) 195: char *s; 196: short no; 197: { 198: register struct pftab *pp; 199: 200: lastpf++; 201: if (table == 0) 202: return; 203: if (no == zpfcnt) 204: cPANIC(); 205: pp = &zpf[no]; 206: pp->pfname = s; 207: pp->pfline = line; 208: pp->pfcnt = nowcnt(); 209: pp->pflev = cbn; 210: } 211: 212: prttab() 213: { 214: register i, j; 215: register struct pftab *zpfp; 216: 217: if (profile == 0 && table == 0) 218: return; 219: if (cnts != zcnt || lastpf != zpfcnt) 220: cPANIC(); 221: if (table == 0) 222: return; 223: if (profile) 224: printf("\f\n"); 225: header(); 226: printf("\n\tLine\t Count\n\n"); 227: zpfp = zpf; 228: for (i = 0; i < zpfcnt; i++) { 229: printf("\t%4d\t%8ld\t", zpfp->pfline, zpfp->pfcnt); 230: if (!justify) 231: for (j = zpfp->pflev * unit; j > 1; j--) 232: putchar(' '); 233: printf("%s\n", zpfp->pfname); 234: zpfp++; 235: } 236: } 237: 238: nowcntr() 239: { 240: 241: return (px.counter); 242: } 243: 244: long nowcnt() 245: { 246: 247: return (px.ntimes); 248: } 249: 250: long cntof(pxc) 251: struct pxcnt *pxc; 252: { 253: 254: if (profile == 0 && table == 0) 255: return; 256: return (pxc->ntimes); 257: } 258: 259: setcnt(l) 260: long l; 261: { 262: 263: if (profile == 0 && table == 0) 264: return; 265: px.counter = --gcountr; 266: px.ntimes = l; 267: px.gos = gocnt; 268: px.printed = 0; 269: } 270: 271: savecnt(pxc) 272: register struct pxcnt *pxc; 273: { 274: 275: if (profile == 0 && table == 0) 276: return; 277: pxc->ntimes = px.ntimes; 278: pxc->counter = px.counter; 279: pxc->gos = px.gos; 280: pxc->printed = 1; 281: } 282: 283: rescnt(pxc) 284: register struct pxcnt *pxc; 285: { 286: 287: if (profile == 0 && table == 0) 288: return; 289: px.ntimes = pxc->ntimes; 290: px.counter = pxc->counter; 291: px.gos = gocnt; 292: px.printed = pxc->printed; 293: return (gocnt != pxc->gos); 294: } 295: 296: getcnt() 297: { 298: 299: if (profile == 0 && table == 0) 300: return; 301: if (cnts == zcnt) 302: cPANIC(); 303: px.counter = cnts; 304: px.ntimes = zbuf[cnts]; 305: px.gos = gocnt; 306: px.printed = 0; 307: ++cnts; 308: } 309: 310: unprint() 311: { 312: 313: px.printed = 0; 314: } 315: 316: /* 317: * Control printing of '|' 318: * when profiling. 319: */ 320: STATIC char nobar; 321: 322: baroff() 323: { 324: 325: nobar = 1; 326: } 327: 328: baron() 329: { 330: 331: nobar = 0; 332: } 333: 334: /* 335: * Do we want cnt and/or '|' on this line ? 336: * 1 = count and '|' 337: * 0 = only '|' 338: * -1 = spaces only 339: */ 340: shudpcnt() 341: { 342: 343: register i; 344: 345: if (nobar) 346: return (-1); 347: i = px.printed; 348: px.printed = 1; 349: return (i == 0); 350: } 351: 352: STATIC char mism[] = "Program and counter data do not correspond\n"; 353: 354: cPANIC() 355: { 356: 357: printf("cnts %d zcnt %d, lastpf %d zpfcnt %d\n", 358: cnts, zcnt, lastpf, zpfcnt); 359: flush(); 360: write(2, mism, sizeof mism); 361: pexit(ERRS); 362: }