From b7c9bf289f096dd5338f37a4656f13d7b982fd33 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Thu, 9 May 2002 14:54:19 +0200 Subject: final.c (end_final): Use C trees to output data structures for profiling. * final.c (end_final): Use C trees to output data structures for profiling. * Makefile.in (LIBGCC_DEPS): Added missing dependency on gcov-io.h (profile.o): New dependency profile.h (final.o): New dependency profile.h * profile.h: New file. New global structure profile_info. * final.h (count_edges_instrumented_now): Declare. (current_function_cfg_checksum): Declare. (function_list): New structure. (functions_head, functions_tail): New static variables. (end_final): Emits more data, removed some -ax stuff. (final): Stores function names and chcksums. * gcov-io.h (__write_gcov_string): New function. (__read_gcov_string): New function. * gcov.c (read_profile): New function. (create_program_flow_graph): Uses read_profile instead of reading da_file. (read_files): Removed da_file checking, it's done by read_profile now. * libgcc2.c (bb_function_info): New structure. (bb): New field in structure, removed some -ax stuff. (__bb_exit_func): Changed structure of da_file. * profile.c (count_edges_instrumented_now): New global variable. (current_function_cfg_checksum): New global variable. (max_counter_in_program): New global variable. (get_exec_counts): New function. (compute_checksum): New function. (instrument_edges): Sets count_edges_instrumented_now. (compute_branch_probabilities): Uses get_exec_counts instead of reading da_file. (branch_prob): Calls compute_checksum and writes extra data to bbg_file. (init_branch_prob): Removed da_file checking, done in get_exec_counts now. (end_branch_prob): Removed da_file checking, done in get_exec_counts now. * gcov.texi: Updated information about gcov file format. Co-Authored-By: Pavel Nejedly From-SVN: r53326 --- gcc/gcov.c | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 159 insertions(+), 23 deletions(-) (limited to 'gcc/gcov.c') diff --git a/gcc/gcov.c b/gcc/gcov.c index 3bb2ce1..fbc3d00 100644 --- a/gcc/gcov.c +++ b/gcc/gcov.c @@ -232,6 +232,7 @@ static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN; static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN; static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *)); static struct adj_list *reverse_arcs PARAMS ((struct adj_list *)); +static gcov_type *read_profile PARAMS ((char *, long, int)); static void create_program_flow_graph PARAMS ((struct bb_info_list *)); static void solve_program_flow_graph PARAMS ((struct bb_info_list *)); static void calculate_branch_probs PARAMS ((struct bb_info_list *, int, @@ -538,6 +539,130 @@ reverse_arcs (arcptr) return prev; } +/* Reads profiles from the .da file and compute a hybrid profile. */ + +static gcov_type * +read_profile (function_name, cfg_checksum, instr_arcs) + char *function_name; + long cfg_checksum; + int instr_arcs; +{ + int i; + int okay = 1; + gcov_type *profile; + char *function_name_buffer; + int function_name_buffer_len; + + profile = xmalloc (sizeof (gcov_type) * instr_arcs); + rewind (da_file); + function_name_buffer_len = strlen (function_name) + 1; + function_name_buffer = xmalloc (function_name_buffer_len + 1); + + for (i = 0; i < instr_arcs; i++) + profile[i] = 0; + + if (!da_file) + return profile; + + while (1) + { + long magic, extra_bytes; + long func_count; + int i; + + if (__read_long (&magic, da_file, 4) != 0) + break; + + if (magic != -123) + { + okay = 0; + break; + } + + if (__read_long (&func_count, da_file, 4) != 0) + { + okay = 0; + break; + } + + if (__read_long (&extra_bytes, da_file, 4) != 0) + { + okay = 0; + break; + } + + /* skip extra data emited by __bb_exit_func. */ + fseek (da_file, extra_bytes, SEEK_CUR); + + for (i = 0; i < func_count; i++) + { + long arc_count; + long chksum; + int j; + + if (__read_gcov_string + (function_name_buffer, function_name_buffer_len, da_file, + -1) != 0) + { + okay = 0; + break; + } + + if (__read_long (&chksum, da_file, 4) != 0) + { + okay = 0; + break; + } + + if (__read_long (&arc_count, da_file, 4) != 0) + { + okay = 0; + break; + } + + if (strcmp (function_name_buffer, function_name) != 0 + || arc_count != instr_arcs || chksum != cfg_checksum) + { + /* skip */ + if (fseek (da_file, arc_count * 8, SEEK_CUR) < 0) + { + okay = 0; + break; + } + } + else + { + gcov_type tmp; + + for (j = 0; j < arc_count; j++) + if (__read_gcov_type (&tmp, da_file, 8) != 0) + { + okay = 0; + break; + } + else + { + profile[j] += tmp; + } + } + } + + if (!okay) + break; + + } + + free (function_name_buffer); + + if (!okay) + { + fprintf (stderr, ".da file corrupted!\n"); + free (profile); + abort (); + } + + return profile; +} /* Construct the program flow graph from the .bbg file, and read in the data in the .da file. */ @@ -550,6 +675,29 @@ create_program_flow_graph (bptr) int i; struct adj_list *arcptr; struct bb_info *bb_graph; + long cfg_checksum; + long instr_arcs = 0; + gcov_type *profile; + int profile_pos = 0; + char *function_name; + long function_name_len, tmp; + + /* Read function name. */ + __read_long (&tmp, bbg_file, 4); /* ignore -1. */ + __read_long (&function_name_len, bbg_file, 4); + function_name = xmalloc (function_name_len + 1); + fread (function_name, 1, function_name_len + 1, bbg_file); + + /* Skip padding. */ + tmp = (function_name_len + 1) % 4; + + if (tmp) + fseek (bbg_file, 4 - tmp, SEEK_CUR); + + __read_long (&tmp, bbg_file, 4); /* ignore -1. */ + + /* Read the cfg checksum. */ + __read_long (&cfg_checksum, bbg_file, 4); /* Read the number of blocks. */ __read_long (&num_blocks, bbg_file, 4); @@ -579,7 +727,10 @@ create_program_flow_graph (bptr) init_arc (arcptr, src, dest, bb_graph); __read_long (&flag_bits, bbg_file, 4); - arcptr->on_tree = flag_bits & 0x1; + if (flag_bits & 0x1) + arcptr->on_tree++; + else + instr_arcs++; arcptr->fake = !! (flag_bits & 0x2); arcptr->fall_through = !! (flag_bits & 0x4); } @@ -601,6 +752,10 @@ create_program_flow_graph (bptr) if (bb_graph[i].succ) bb_graph[i].succ = reverse_arcs (bb_graph[i].succ); + /* Read profile from the .da file. */ + + profile = read_profile (function_name, cfg_checksum, instr_arcs); + /* For each arc not on the spanning tree, set its execution count from the .da file. */ @@ -613,15 +768,13 @@ create_program_flow_graph (bptr) for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next) if (! arcptr->on_tree) { - gcov_type tmp_count = 0; - if (da_file && __read_gcov_type (&tmp_count, da_file, 8)) - abort (); - - arcptr->arc_count = tmp_count; + arcptr->arc_count = profile[profile_pos++]; arcptr->count_valid = 1; bb_graph[i].succ_count--; bb_graph[arcptr->target].pred_count--; } + free (profile); + free (function_name); } static void @@ -755,12 +908,6 @@ read_files () struct stat buf; struct bb_info_list *list_end = 0; struct bb_info_list *b_ptr; - long total; - - /* Read and ignore the first word of the .da file, which is the count of - how many numbers follow. */ - if (da_file && __read_long (&total, da_file, 8)) - abort (); while (! feof (bbg_file)) { @@ -781,17 +928,6 @@ read_files () ungetc (getc (bbg_file), bbg_file); } - /* Check to make sure the .da file data is valid. */ - - if (da_file) - { - if (feof (da_file)) - fnotice (stderr, ".da file contents exhausted too early\n"); - /* Should be at end of file now. */ - if (__read_long (&total, da_file, 8) == 0) - fnotice (stderr, ".da file contents not exhausted\n"); - } - /* Calculate all of the basic block execution counts and branch taken probabilities. */ -- cgit v1.1