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