lint.
[unix-history] / usr / src / usr.bin / gprof / gprof.c
CommitLineData
3966d652 1#ifndef lint
35e3e365 2 static char *sccsid = "@(#)gprof.c 1.5 (Berkeley) %G%";
3966d652
PK
3#endif lint
4
31f0a970 5#include "gprof.h"
3966d652
PK
6
7main(argc, argv)
8 int argc;
9 char **argv;
10{
11
12 --argc;
13 argv++;
14 debug = 0;
15 while ( *argv != 0 && **argv == '-' ) {
16 (*argv)++;
17 if ( **argv == 'd' ) {
18 (*argv)++;
19 debug |= atoi( *argv );
20 debug |= ANYDEBUG;
21# ifdef DEBUG
22 printf( "[main] debug = %d\n" , debug );
23# endif DEBUG
24 } else if ( **argv == 'z' ) {
25 zflg++;
29da1d26
PK
26 } else if ( **argv == 'c' ) {
27 cflag++;
3966d652
PK
28 }
29 argv++;
30 }
31 if ( *argv != 0 ) {
32 a_outname = *argv;
33 argv++;
34 } else {
35 a_outname = A_OUTNAME;
36 }
37 if ( *argv != 0 ) {
31f0a970 38 gmonname = *argv;
3966d652
PK
39 argv++;
40 } else {
31f0a970 41 gmonname = GMONNAME;
3966d652
PK
42 }
43 /*
44 * get information about a.out file.
45 */
46 getnfile();
47 /*
48 * get information about mon.out file(s).
49 */
31f0a970 50 getpfile( gmonname );
3966d652
PK
51 /*
52 * assign samples to procedures
53 */
54 asgnsamples();
55 /*
56 * print the usual profile
57 */
58 printprof();
59 /*
60 * assemble and print the dynamic profile
61 */
62 doarcs();
63 done();
64}
65
3966d652
PK
66/*
67 * Set up string and symbol tables from a.out.
29da1d26 68 * and optionally the text space.
3966d652
PK
69 * On return symbol table is sorted by value.
70 */
71getnfile()
72{
73 FILE *nfile;
74
75 nfile = fopen( a_outname ,"r");
76 if (nfile == NULL) {
77 perror( a_outname );
78 done();
79 }
80 fread(&xbuf, 1, sizeof(xbuf), nfile);
81 if (N_BADMAG(xbuf)) {
82 fprintf(stderr, "%s: bad format\n", a_outname );
83 done();
84 }
85 getstrtab(nfile);
86 getsymtab(nfile);
29da1d26 87 gettextspace( nfile );
3966d652
PK
88 qsort(nl, nname, sizeof(nltype), valcmp);
89 fclose(nfile);
90# ifdef DEBUG
91 if ( debug & AOUTDEBUG ) {
92 register int j;
93
94 for (j = 0; j < nname; j++){
95 printf("[getnfile] 0X%08x\t%s\n", nl[j].value, nl[j].name);
96 }
97 }
98# endif DEBUG
99}
100
101getstrtab(nfile)
102 FILE *nfile;
103{
104
105 fseek(nfile, (long)(N_SYMOFF(xbuf) + xbuf.a_syms), 0);
106 if (fread(&ssiz, sizeof (ssiz), 1, nfile) == 0) {
107 fprintf(stderr, "%s: no string table (old format?)\n", a_outname );
108 done();
109 }
110 strtab = (char *)calloc(ssiz, 1);
111 if (strtab == NULL) {
112 fprintf(stderr, "%s: no room for %d bytes of string table",
113 a_outname , ssiz);
114 done();
115 }
116 if (fread(strtab+sizeof(ssiz), ssiz-sizeof(ssiz), 1, nfile) != 1) {
117 fprintf(stderr, "%s: error reading string table\n", a_outname );
118 done();
119 }
120}
121
122 /*
123 * Read in symbol table
124 */
125getsymtab(nfile)
126 FILE *nfile;
127{
128 register long i;
129 int askfor;
130 struct nlist nbuf;
131
132 /* pass1 - count symbols */
133 fseek(nfile, (long)N_SYMOFF(xbuf), 0);
134 nname = 0;
135 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
136 fread(&nbuf, sizeof(nbuf), 1, nfile);
137 if ( nbuf.n_type != N_TEXT+N_EXT ) {
138 continue;
139 }
140 nname++;
141 }
142 if (nname == 0) {
143 fprintf(stderr, "%s: no symbols\n", a_outname );
144 done();
145 }
146 /*
147 * ask also for CYCLEFRACTION extra namelist entries for
148 * cycle entries. these hide out at the end of the namelist
149 * and aren't accessed unless the whole namelist (nname+ncycles)
150 * is sorted and searched.
151 */
152 ncycles = nname * CYCLEFRACTION;
153 askfor = nname + 1 + ncycles;
154 nl = (nltype *) calloc( askfor , sizeof(nltype) );
155 if (nl == 0) {
156 fprintf(stderr, "prof: No room for %d bytes of symbol table\n",
157 askfor * sizeof(nltype) );
158 done();
159 }
160
161 /* pass2 - read symbols */
162 fseek(nfile, (long)N_SYMOFF(xbuf), 0);
163 npe = nl;
164 nname = 0;
165 for (i = xbuf.a_syms; i > 0; i -= sizeof(struct nlist)) {
166 fread(&nbuf, sizeof(nbuf), 1, nfile);
167 if ( nbuf.n_type != N_TEXT+N_EXT ) {
168 continue;
169 }
170 npe->value = nbuf.n_value;
171 npe->name = strtab+nbuf.n_un.n_strx;
172# ifdef DEBUG
173 if ( debug & AOUTDEBUG ) {
174 printf( "[getsymtab] %d %s 0x%08x\n" ,
175 nname , npe -> name , npe -> value );
176 }
177# endif DEBUG
178 npe++;
179 nname++;
180 }
181 npe->value = -1;
182 npe++;
183}
184
29da1d26
PK
185 /*
186 * read in the text space of an a.out file
187 */
188gettextspace( nfile )
189 FILE *nfile;
190{
191 unsigned char *malloc();
192
193 if ( cflag == 0 ) {
194 return;
195 }
196 textspace = malloc( xbuf.a_text );
197 if ( textspace == 0 ) {
198 fprintf( stderr , "gprof: ran out room for %d bytes of text space: " );
199 fprintf( stderr , "can't do -c\n" , xbuf.a_text );
200 return;
201 }
202 (void) fseek( nfile , N_TXTOFF( xbuf ) , 0 );
203 if ( fread( textspace , 1 , xbuf.a_text , nfile ) != xbuf.a_text ) {
204 fprintf( stderr , "couldn't read text space: " );
205 fprintf( stderr , "can't do -c\n" , xbuf.a_text );
206 free( textspace );
207 textspace = 0;
208 return;
209 }
210}
3966d652 211 /*
31f0a970 212 * information from a gmon.out file is in two parts:
3966d652
PK
213 * an array of sampling hits within pc ranges,
214 * and the arcs.
215 */
216getpfile(filename)
217 char *filename;
218{
219 FILE *pfile;
220 FILE *openpfile();
221 struct rawarc arc;
222
223 pfile = openpfile(filename);
224 readsamples(pfile);
225 /*
226 * the rest of the file consists of
227 * a bunch of <from,self,count> tuples.
228 */
229 while ( fread( &arc , sizeof arc , 1 , pfile ) == 1 ) {
230# ifdef DEBUG
231 if ( debug & SAMPLEDEBUG ) {
06ac0fb1 232 printf( "[getpfile] frompc 0x%x selfpc 0x%x count %d\n" ,
3966d652
PK
233 arc.raw_frompc , arc.raw_selfpc , arc.raw_count );
234 }
235# endif DEBUG
236 /*
237 * add this arc
238 */
239 tally( &arc );
240 }
241 fclose(pfile);
242}
243
35e3e365
PK
244FILE *
245openpfile(filename)
3966d652
PK
246 char *filename;
247{
248 FILE *pfile;
249
250 if((pfile = fopen(filename, "r")) == NULL) {
251 perror(filename);
252 done();
253 }
254 fread(&h, sizeof(struct hdr), 1, pfile);
06ac0fb1
PK
255 s_lowpc = (unsigned long) h.lowpc;
256 s_highpc = (unsigned long) h.highpc;
3966d652
PK
257 lowpc = h.lowpc - (UNIT *)0;
258 highpc = h.highpc - (UNIT *)0;
259 sampbytes = h.ncnt - sizeof(struct hdr);
260 nsamples = sampbytes / sizeof (unsigned UNIT);
261 return(pfile);
262}
263
264tally( rawp )
265 struct rawarc *rawp;
266{
267 nltype *parentp;
268 nltype *childp;
3966d652
PK
269
270 parentp = nllookup( rawp -> raw_frompc );
271 childp = nllookup( rawp -> raw_selfpc );
272 childp -> ncall += rawp -> raw_count;
273# ifdef DEBUG
274 if ( debug & TALLYDEBUG ) {
275 printf( "[tally] arc from %s to %s traversed %d times\n" ,
276 parentp -> name , childp -> name , rawp -> raw_count );
277 }
278# endif DEBUG
29da1d26 279 addarc( parentp , childp , rawp -> raw_count );
3966d652
PK
280}
281
282valcmp(p1, p2)
283 nltype *p1, *p2;
284{
285 if ( p1 -> value < p2 -> value ) {
286 return LESSTHAN;
287 }
288 if ( p1 -> value > p2 -> value ) {
289 return GREATERTHAN;
290 }
291 return EQUALTO;
292}
293
294readsamples(pfile)
295 FILE *pfile;
296{
297 register i;
298 unsigned UNIT sample;
299
300 if (samples == 0) {
301 samples = (unsigned UNIT *) calloc(sampbytes, sizeof (unsigned UNIT));
302 if (samples == 0) {
303 fprintf( stderr , "prof: No room for %d sample pc's\n",
304 sampbytes / sizeof (unsigned UNIT));
305 done();
306 }
307 }
308 for (i = 0; i < nsamples; i++) {
309 fread(&sample, sizeof (unsigned UNIT), 1, pfile);
310 if (feof(pfile))
311 break;
312 samples[i] += sample;
313 }
314 if (i != nsamples) {
315 fprintf(stderr,
316 "prof: unexpected EOF after reading %d/%d samples\n",
317 --i, nsamples);
318 done();
319 }
320}
321
322/*
323 * Assign samples to the procedures to which they belong.
324 */
325asgnsamples()
326{
327 register int j;
328 unsigned UNIT ccnt;
329 double time;
330 unsigned long pcl, pch;
331 register int i;
35e3e365 332 unsigned long overlap;
3966d652
PK
333 unsigned long svalue0, svalue1;
334
335 /* read samples and assign to namelist symbols */
336 scale = highpc - lowpc;
337 scale /= nsamples;
338 for (i=0; i < nsamples; i++) {
339 ccnt = samples[i];
340 if (ccnt == 0)
341 continue;
342 pcl = lowpc + scale*i;
343 pch = lowpc + scale*(i+1);
344 time = ccnt;
345# ifdef DEBUG
346 if ( debug & SAMPLEDEBUG ) {
347 printf( "[asgnsamples] ccnt %d time %f totime %f\n" ,
348 ccnt , time , totime );
349 }
350# endif DEBUG
351 totime += time;
352 for (j=0; j<nname; j++) {
353 svalue0 = nl[j].value / sizeof(UNIT);
354 svalue1 = nl[j+1].value / sizeof(UNIT);
355 if (pch < svalue0)
356 break;
357 if (pcl >= svalue1)
358 continue;
359 overlap=min(pch,svalue1) - max(pcl,svalue0);
360 if (overlap>0) {
361# ifdef DEBUG
362 if ( debug & SAMPLEDEBUG ) {
363 printf( "[asgnsamples] %s gets %f ticks\n" ,
364 nl[j].name , overlap*time/scale );
365 }
366# endif DEBUG
367 nl[j].time += overlap*time/scale;
368 }
369 }
370 }
371# ifdef DEBUG
372 if ( debug & SAMPLEDEBUG ) {
373 printf( "[asgnsamples] totime %f\n" , totime );
374 }
375# endif DEBUG
376 if (totime==0.0) {
377 fprintf( stderr , "No time accumulated\n" );
378 totime=1.0;
379 }
380}
381
382
35e3e365 383unsigned long
3966d652 384min(a, b)
35e3e365 385 unsigned long a,b;
3966d652
PK
386{
387 if (a<b)
388 return(a);
389 return(b);
390}
391
35e3e365 392unsigned long
3966d652 393max(a, b)
35e3e365 394 unsigned long a,b;
3966d652
PK
395{
396 if (a>b)
397 return(a);
398 return(b);
399}
400
3966d652
PK
401done()
402{
403
404 exit(0);
405}