]>
git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gprof/basic_blocks.c
2 * Basic-block level related code: reading/writing of basic-block info
3 * to/from gmon.out; computing and formatting of basic-block related
8 #include "basic_blocks.h"
13 #include "libiberty.h"
19 * Default option values:
21 bool bb_annotate_all_lines
= FALSE
;
23 int bb_table_length
= 10;
26 * Variables used to compute annotated source listing stats:
28 static long num_executable_lines
;
29 static long num_lines_executed
;
33 * Helper for sorting. Compares two basic-blocks and returns result
34 * such that sorting will be increasing according to filename, line
35 * number, and basic-block address (in that order).
38 DEFUN(cmp_bb
, (lp
, rp
), const void *lp AND
const void *rp
)
41 const Sym
*left
= *(const Sym
**)lp
;
42 const Sym
*right
= *(const Sym
**)rp
;
44 if (left
->file
&& right
->file
) {
45 r
= strcmp(left
->file
->name
, right
->file
->name
);
50 if (left
->line_num
!= right
->line_num
) {
51 return left
->line_num
- right
->line_num
;
55 if (left
->addr
< right
->addr
) {
57 } else if (left
->addr
> right
->addr
) {
66 * Helper for sorting. Order basic blocks in decreasing number of
67 * calls, ties are broken in increasing order of line numbers.
70 DEFUN(cmp_ncalls
, (lp
, rp
), const void *lp AND
const void *rp
)
72 const Sym
*left
= *(const Sym
**)lp
;
73 const Sym
*right
= *(const Sym
**)rp
;
81 if (right
->ncalls
!= left
->ncalls
) {
82 return right
->ncalls
- left
->ncalls
;
85 return left
->line_num
- right
->line_num
;
90 * Skip over variable length string.
93 DEFUN(fskip_string
, (fp
), FILE *fp
)
97 while ((ch
= fgetc(fp
)) != EOF
) {
106 * Read a basic-block record from file IFP. FILENAME is the name
107 * of file IFP and is provided for formatting error-messages only.
110 DEFUN(bb_read_rec
, (ifp
, filename
), FILE *ifp AND
const char *filename
)
117 if (fread(&nblocks
, sizeof(nblocks
), 1, ifp
) != 1) {
118 fprintf(stderr
, "%s: %s: unexpected end of file\n", whoami
, filename
);
122 nblocks
= bfd_get_32(core_bfd
, (bfd_byte
*) &nblocks
);
123 if (gmon_file_version
== 0) {
127 for (b
= 0; b
< nblocks
; ++b
) {
128 if (gmon_file_version
== 0) {
131 * Version 0 had lots of extra stuff that we don't
132 * care about anymore.
134 if ((fread(&ncalls
, sizeof(ncalls
), 1, ifp
) != 1)
135 || (fread(&addr
, sizeof(addr
), 1, ifp
) != 1)
136 || (fskip_string(ifp
), FALSE
)
137 || (fskip_string(ifp
), FALSE
)
138 || (fread(&line_num
, sizeof(line_num
), 1, ifp
) != 1))
144 if (fread(&addr
, sizeof(addr
), 1, ifp
) != 1
145 || fread(&ncalls
, sizeof(ncalls
), 1, ifp
) != 1)
153 * Basic-block execution counts are meaningful only if we're
154 * profiling at the line-by-line level:
156 if (line_granularity
) {
158 /* convert from target to host endianness: */
160 addr
= get_vma(core_bfd
, (bfd_byte
*) &addr
);
162 sym
= sym_lookup(&symtab
, addr
);
163 sym
->is_bb_head
= TRUE
;
164 sym
->ncalls
+= bfd_get_32(core_bfd
, (bfd_byte
*)&ncalls
);
166 DBG(BBDEBUG
, printf("[bb_read_rec] 0x%lx->0x%lx (%s) cnt=%d\n",
167 addr
, sym
->addr
, sym
->name
, sym
->ncalls
));
169 static bool user_warned
= FALSE
;
174 "%s: warning: ignoring basic-block exec counts (use -l or --line)\n",
184 * Write all basic-blocks with non-zero counts to file OFP. FILENAME
185 * is the name of OFP and is provided for producing error-messages
189 DEFUN(bb_write_blocks
, (ofp
, filename
), FILE *ofp AND
const char *filename
)
191 const unsigned char tag
= GMON_TAG_BB_COUNT
;
197 /* count how many non-zero blocks with have: */
199 for (sym
= symtab
.base
; sym
< symtab
.limit
; ++sym
) {
200 if (sym
->ncalls
> 0) {
206 bfd_put_32(core_bfd
, nblocks
, (bfd_byte
*) &nblocks
);
207 if (fwrite(&tag
, sizeof(tag
), 1, ofp
) != 1
208 || fwrite(&nblocks
, sizeof(nblocks
), 1, ofp
) != 1)
215 for (sym
= symtab
.base
; sym
< symtab
.limit
; ++sym
) {
216 if (sym
->ncalls
== 0) {
220 put_vma(core_bfd
, sym
->addr
, (bfd_byte
*) &addr
);
221 bfd_put_32(core_bfd
, sym
->ncalls
, (bfd_byte
*) &ncalls
);
223 if (fwrite(&addr
, sizeof(addr
), 1, ofp
) != 1
224 || fwrite(&ncalls
, sizeof(ncalls
), 1, ofp
) != 1)
230 } /* bb_write_blocks */
234 * Output basic-block statistics in a format that is easily parseable.
235 * Current the format is:
237 * <filename>:<line-number>: (<function-name>:<bb-addr): <ncalls>
240 DEFUN_VOID(print_exec_counts
)
242 Sym
**sorted_bbs
, *sym
;
246 first_output
= FALSE
;
251 /* sort basic-blocks according to function name and line number: */
253 sorted_bbs
= (Sym
**)xmalloc(symtab
.len
* sizeof(sorted_bbs
[0]));
255 for (sym
= symtab
.base
; sym
< symtab
.limit
; ++sym
) {
257 * Accept symbol if it's the start of a basic-block and it is
258 * called at least bb_min_calls times and if it's in the
259 * INCL_EXEC table or there is no INCL_EXEC table and it does
260 * not appear in the EXCL_EXEC table.
262 if (sym
->is_bb_head
&& sym
->ncalls
>= bb_min_calls
263 && (sym_lookup(&syms
[INCL_EXEC
], sym
->addr
)
264 || (syms
[INCL_EXEC
].len
== 0
265 && !sym_lookup(&syms
[EXCL_EXEC
], sym
->addr
))))
267 sorted_bbs
[len
++] = sym
;
270 qsort(sorted_bbs
, len
, sizeof(sorted_bbs
[0]), cmp_bb
);
272 /* output basic-blocks: */
274 for (i
= 0; i
< len
; ++i
) {
276 printf("%s:%d: (%s:0x%lx) %d executions\n",
277 sym
->file
? sym
->file
->name
: "<unknown>", sym
->line_num
,
278 sym
->name
, sym
->addr
, sym
->ncalls
);
281 } /* print_exec_counts */
285 * Helper for bb_annotated_source: format annotation containing
286 * number of line executions.
289 DEFUN(annotate_with_count
, (buf
, width
, line_num
, arg
),
290 char *buf AND
int width AND
int line_num AND
void *arg
)
292 Source_File
*sf
= arg
;
295 static long last_count
;
302 if (line_num
<= sf
->num_lines
) {
303 b
= sf
->line
[line_num
- 1];
308 ++num_executable_lines
;
312 ++num_lines_executed
;
314 if (cnt
< 0 && bb_annotate_all_lines
) {
320 } else if (cnt
< bb_min_calls
) {
321 strcpy(buf
, " ##### -> ");
323 sprintf(buf
, "%12ld -> ", cnt
);
326 } /* annotate_with_count */
330 * Annotate the files named in SOURCE_FILES with basic-block statistics
331 * (execution counts). After each source files, a few statistics
332 * regarding that source file are printed.
335 DEFUN_VOID(print_annotated_source
)
337 Sym
*sym
, *line_stats
, *new_line
;
343 * Find maximum line number for each source file that user is
346 for (sym
= symtab
.base
; sym
< symtab
.limit
; ++sym
) {
348 * Accept symbol if it's file is known, its line number is
349 * bigger than anything we have seen for that file so far and
350 * if it's in the INCL_ANNO table or there is no INCL_ANNO
351 * table and it does not appear in the EXCL_ANNO table.
353 if (sym
->file
&& sym
->line_num
> sym
->file
->num_lines
354 && (sym_lookup(&syms
[INCL_ANNO
], sym
->addr
)
355 || (syms
[INCL_ANNO
].len
== 0
356 && !sym_lookup(&syms
[EXCL_ANNO
], sym
->addr
))))
358 sym
->file
->num_lines
= sym
->line_num
;
362 /* allocate line descriptors: */
364 for (sf
= first_src_file
; sf
; sf
= sf
->next
) {
365 if (sf
->num_lines
> 0) {
366 sf
->line
= (void*) xmalloc(sf
->num_lines
* sizeof(sf
->line
[0]));
367 memset(sf
->line
, 0, sf
->num_lines
* sizeof(sf
->line
[0]));
371 /* count executions per line: */
373 for (sym
= symtab
.base
; sym
< symtab
.limit
; ++sym
) {
374 if (sym
->is_bb_head
&& sym
->file
&& sym
->file
->num_lines
375 && (sym_lookup(&syms
[INCL_ANNO
], sym
->addr
)
376 || (syms
[INCL_ANNO
].len
== 0
377 && !sym_lookup(&syms
[EXCL_ANNO
], sym
->addr
))))
379 sym
->file
->ncalls
+= sym
->ncalls
;
380 line_stats
= sym
->file
->line
[sym
->line_num
- 1];
382 /* common case has at most one basic-block per source line: */
383 sym
->file
->line
[sym
->line_num
- 1] = sym
;
384 } else if (!line_stats
->addr
) {
385 /* sym is the 3rd .. nth basic block for this line: */
386 line_stats
->ncalls
+= sym
->ncalls
;
388 /* sym is the second basic block for this line */
389 new_line
= (Sym
*) xmalloc(sizeof(*new_line
));
390 *new_line
= *line_stats
;
392 new_line
->ncalls
+= sym
->ncalls
;
393 sym
->file
->line
[sym
->line_num
- 1] = new_line
;
398 /* plod over source files, annotating them: */
400 for (sf
= first_src_file
; sf
; sf
= sf
->next
) {
401 if (!sf
->num_lines
|| (ignore_zeros
&& sf
->ncalls
== 0)) {
405 num_executable_lines
= num_lines_executed
= 0;
406 ofp
= annotate_source(sf
, 16, annotate_with_count
, sf
);
411 if (bb_table_length
> 0) {
412 fprintf(ofp
, "\n\nTop %d Lines:\n\n Line Count\n\n",
415 /* abuse line arrays---it's not needed anymore: */
416 qsort(sf
->line
, sf
->num_lines
, sizeof(sf
->line
[0]), cmp_ncalls
);
417 table_len
= bb_table_length
;
418 if (table_len
> sf
->num_lines
) {
419 table_len
= sf
->num_lines
;
421 for (i
= 0; i
< table_len
; ++i
) {
423 if (!sym
|| sym
->ncalls
<= 0) {
426 fprintf(ofp
, "%9d %10d\n", sym
->line_num
, sym
->ncalls
);
433 fprintf(ofp
, "\nExecution Summary:\n\n");
434 fprintf(ofp
, "%9ld Executable lines in this file\n",
435 num_executable_lines
);
436 fprintf(ofp
, "%9ld Lines executed\n", num_lines_executed
);
437 fprintf(ofp
, "%9.2f Percent of the file executed\n",
439 ? 100.0 * num_lines_executed
/ (double) num_executable_lines
441 fprintf(ofp
, "\n%9d Total number of line executions\n", sf
->ncalls
);
442 fprintf(ofp
, "%9.2f Average executions per line\n",
444 ? sf
->ncalls
/ (double) num_executable_lines
450 } /* print_annotated_source */
452 /*** end of basic_block.c ***/