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
getit(fp)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 */
getpmon(fp)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
pmnospac()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
getcore(fp)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
pmread()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
cnttab(s,no)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
prttab()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
nowcntr()239 nowcntr()
240 {
241
242 return (px.counter);
243 }
244
nowcnt()245 long nowcnt()
246 {
247
248 return (px.ntimes);
249 }
250
cntof(pxc)251 long cntof(pxc)
252 struct pxcnt *pxc;
253 {
254
255 if (profile == 0 && table == 0)
256 return;
257 return (pxc->ntimes);
258 }
259
setcnt(l)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
savecnt(pxc)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
rescnt(pxc)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
getcnt()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
unprint()311 unprint()
312 {
313
314 px.printed = 0;
315 }
316
317 /*
318 * Control printing of '|'
319 * when profiling.
320 */
321 STATIC char nobar;
322
baroff()323 baroff()
324 {
325
326 nobar = 1;
327 }
328
baron()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 */
shudpcnt()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
cPANIC()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