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