diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-05-09 12:54:19 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2002-05-09 12:54:19 +0000 |
commit | 90c2be4439c656f63074408d6c91442511a9e061 (patch) | |
tree | da04474c0297ae3c91b3bdce0c519ca2f9d2e5a8 /gcc/libgcc2.c | |
parent | 40734805198ef874623eb7be9ec3de9251c799b7 (diff) | |
download | gcc-90c2be4439c656f63074408d6c91442511a9e061.tar.gz |
* 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@53326 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/libgcc2.c')
-rw-r--r-- | gcc/libgcc2.c | 204 |
1 files changed, 115 insertions, 89 deletions
diff --git a/gcc/libgcc2.c b/gcc/libgcc2.c index a06b7951ab9..6c004a59a3b 100644 --- a/gcc/libgcc2.c +++ b/gcc/libgcc2.c @@ -1238,12 +1238,11 @@ __eprintf (const char *string, const char *expression, #ifdef L_bb -#if LONG_TYPE_SIZE == GCOV_TYPE_SIZE -typedef long gcov_type; -#else -typedef long long gcov_type; -#endif - +struct bb_function_info { + long checksum; + int arc_count; + const char *name; +}; /* Structure emitted by -a */ struct bb @@ -1253,14 +1252,10 @@ struct bb gcov_type *counts; long ncounts; struct bb *next; - const unsigned long *addresses; /* Older GCC's did not emit these fields. */ long nwords; - const char **functions; - const long *line_nums; - const char **filenames; - char *flags; + struct bb_function_info *function_infos; }; #ifdef BLOCK_PROFILER_CODE @@ -1283,39 +1278,66 @@ BLOCK_PROFILER_CODE #include <errno.h> #endif +#include <gthr.h> + static struct bb *bb_head; +int __global_counters = 0, __gthreads_active = 0; + void __bb_exit_func (void) { FILE *da_file; - int i; struct bb *ptr; + long n_counters_p = 0; + gcov_type max_counter_p = 0; + gcov_type sum_counters_p = 0; if (bb_head == 0) return; - i = strlen (bb_head->filename) - 3; + /* Calculate overall "statistics". */ + for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) + { + int i; + + n_counters_p += ptr->ncounts; + + for (i = 0; i < ptr->ncounts; i++) + { + sum_counters_p += ptr->counts[i]; + + if (ptr->counts[i] > max_counter_p) + max_counter_p = ptr->counts[i]; + } + } for (ptr = bb_head; ptr != (struct bb *) 0; ptr = ptr->next) { - int firstchar; + gcov_type max_counter_o = 0; + gcov_type sum_counters_o = 0; + int i; + + /* Calculate the per-object statistics. */ - /* Make sure the output file exists - - but don't clobber exiting data. */ - if ((da_file = fopen (ptr->filename, "a")) != 0) - fclose (da_file); + for (i = 0; i < ptr->ncounts; i++) + { + sum_counters_o += ptr->counts[i]; - /* Need to re-open in order to be able to write from the start. */ - da_file = fopen (ptr->filename, "r+b"); + if (ptr->counts[i] > max_counter_o) + max_counter_o = ptr->counts[i]; + } + + /* open the file for appending, creating it if necessary. */ + da_file = fopen (ptr->filename, "ab"); /* Some old systems might not allow the 'b' mode modifier. Therefore, try to open without it. This can lead to a race condition so that when you delete and re-create the file, the file might be opened in text mode, but then, you shouldn't delete the file in the first place. */ if (da_file == 0) - da_file = fopen (ptr->filename, "r+"); + da_file = fopen (ptr->filename, "a"); if (da_file == 0) { fprintf (stderr, "arc profiling: Can't open output file %s.\n", @@ -1341,92 +1363,96 @@ __bb_exit_func (void) } #endif - /* If the file is not empty, and the number of counts in it is the - same, then merge them in. */ - firstchar = fgetc (da_file); - if (firstchar == EOF) + if (__write_long (-123, da_file, 4) != 0) /* magic */ { - if (ferror (da_file)) - { - fprintf (stderr, "arc profiling: Can't read output file "); - perror (ptr->filename); - } + fprintf (stderr, "arc profiling: Error writing output file %s.\n", + ptr->filename); } else { - long n_counts = 0; - - if (ungetc (firstchar, da_file) == EOF) - rewind (da_file); - if (__read_long (&n_counts, da_file, 8) != 0) - { - fprintf (stderr, "arc profiling: Can't read output file %s.\n", - ptr->filename); - continue; - } - if (n_counts == ptr->ncounts) + struct bb_function_info *fn_info; + gcov_type *count_ptr = ptr->counts; + int i; + int count_functions = 0; + + for (fn_info = ptr->function_infos; fn_info->arc_count != -1; + fn_info++) + count_functions++; + + /* number of functions in this block. */ + __write_long (count_functions, da_file, 4); + + /* length of extra data in bytes. */ + __write_long ((4 + 8 + 8) + (4 + 8 + 8), da_file, 4); + + /* overall statistics. */ + /* number of counters. */ + __write_long (n_counters_p, da_file, 4); + /* sum of counters. */ + __write_gcov_type (sum_counters_p, da_file, 8); + /* maximal counter. */ + __write_gcov_type (max_counter_p, da_file, 8); + + /* per-object statistics. */ + /* number of counters. */ + __write_long (ptr->ncounts, da_file, 4); + /* sum of counters. */ + __write_gcov_type (sum_counters_o, da_file, 8); + /* maximal counter. */ + __write_gcov_type (max_counter_o, da_file, 8); + + /* write execution counts for each function. */ + + for (fn_info = ptr->function_infos; fn_info->arc_count != -1; + fn_info++) { - int i; - - for (i = 0; i < n_counts; i++) + /* new function. */ + if (__write_gcov_string + (fn_info->name, strlen (fn_info->name), da_file, -1) != 0) { - gcov_type v = 0; - - if (__read_gcov_type (&v, da_file, 8) != 0) - { - fprintf (stderr, - "arc profiling: Can't read output file %s.\n", - ptr->filename); - break; - } - ptr->counts[i] += v; + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); + break; } - } - } - - rewind (da_file); - - /* ??? Should first write a header to the file. Preferably, a 4 byte - magic number, 4 bytes containing the time the program was - compiled, 4 bytes containing the last modification time of the - source file, and 4 bytes indicating the compiler options used. + if (__write_long (fn_info->checksum, da_file, 4) != 0) + { + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); + break; + } - That way we can easily verify that the proper source/executable/ - data file combination is being used from gcov. */ + if (__write_long (fn_info->arc_count, da_file, 4) != 0) + { + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); + break; + } - if (__write_gcov_type (ptr->ncounts, da_file, 8) != 0) - { + for (i = fn_info->arc_count; i > 0; i--, count_ptr++) + { + if (__write_gcov_type (*count_ptr, da_file, 8) != 0) + break; + } - fprintf (stderr, "arc profiling: Error writing output file %s.\n", - ptr->filename); - } - else - { - int j; - gcov_type *count_ptr = ptr->counts; - int ret = 0; - for (j = ptr->ncounts; j > 0; j--) - { - if (__write_gcov_type (*count_ptr, da_file, 8) != 0) + if (i) /* there was an error */ { - ret = 1; + fprintf (stderr, + "arc profiling: Error writing output file %s.\n", + ptr->filename); break; } - count_ptr++; } - if (ret) - fprintf (stderr, "arc profiling: Error writing output file %s.\n", - ptr->filename); } - if (fclose (da_file) == EOF) + if (fclose (da_file) != 0) fprintf (stderr, "arc profiling: Error closing output file %s.\n", ptr->filename); } - - return; } void @@ -1437,8 +1463,8 @@ __bb_init_func (struct bb *blocks) if (blocks->zero_word) return; - - /* Initialize destructor. */ + + /* Initialize destructor and per-thread data. */ if (!bb_head) atexit (__bb_exit_func); @@ -1451,7 +1477,7 @@ __bb_init_func (struct bb *blocks) /* Called before fork or exec - write out profile information gathered so far and reset it to zero. This avoids duplication or loss of the profile information gathered so far. */ -void +void __bb_fork_func (void) { struct bb *ptr; |