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.3 (Berkeley) 01/03/88"; 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 == NULL) 183 pmnospac(); 184 cp = zpf = pcalloc(zpfcnt * sizeof *zpf, 1); 185 if (cp == NULL) 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 } 363