summaryrefslogtreecommitdiff
path: root/gcc/profile.c
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2002-05-09 12:54:19 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2002-05-09 12:54:19 +0000
commit90c2be4439c656f63074408d6c91442511a9e061 (patch)
treeda04474c0297ae3c91b3bdce0c519ca2f9d2e5a8 /gcc/profile.c
parent40734805198ef874623eb7be9ec3de9251c799b7 (diff)
downloadgcc-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/profile.c')
-rw-r--r--gcc/profile.c281
1 files changed, 234 insertions, 47 deletions
diff --git a/gcc/profile.c b/gcc/profile.c
index 881604e1e27..6fa4e12f031 100644
--- a/gcc/profile.c
+++ b/gcc/profile.c
@@ -49,6 +49,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "basic-block.h"
#include "gcov-io.h"
#include "target.h"
+#include "profile.h"
+#include "libfuncs.h"
#include "langhooks.h"
/* Additional information about the edges we need. */
@@ -92,11 +94,6 @@ static FILE *bb_file;
static char *last_bb_file_name;
-/* Used by final, for allocating the proper amount of storage for the
- instrumented arc execution counts. */
-
-int count_instrumented_edges;
-
/* Collect statistics on the performance of this pass for the entire source
file. */
@@ -118,6 +115,8 @@ static rtx gen_edge_profiler PARAMS ((int));
static void instrument_edges PARAMS ((struct edge_list *));
static void output_gcov_string PARAMS ((const char *, long));
static void compute_branch_probabilities PARAMS ((void));
+static gcov_type * get_exec_counts PARAMS ((void));
+static long compute_checksum PARAMS ((void));
static basic_block find_group PARAMS ((basic_block));
static void union_groups PARAMS ((basic_block, basic_block));
@@ -163,8 +162,9 @@ instrument_edges (el)
}
}
+ profile_info.count_edges_instrumented_now = num_instr_edges;
total_num_edges_instrumented += num_instr_edges;
- count_instrumented_edges = total_num_edges_instrumented;
+ profile_info.count_instrumented_edges = total_num_edges_instrumented;
total_num_blocks_created += num_edges;
if (rtl_dump_file)
@@ -205,6 +205,167 @@ output_gcov_string (string, delimiter)
}
+/* Computes hybrid profile for all matching entries in da_file.
+ Sets max_counter_in_program as a side effect. */
+
+static gcov_type *
+get_exec_counts ()
+{
+ int num_edges = 0;
+ int i;
+ int okay = 1;
+ int mismatch = 0;
+ gcov_type *profile;
+ char *function_name_buffer;
+ int function_name_buffer_len;
+ gcov_type max_counter_in_run;
+
+ profile_info.max_counter_in_program = 0;
+ profile_info.count_profiles_merged = 0;
+
+ /* No .da file, no execution counts. */
+ if (!da_file)
+ return 0;
+
+ /* Count the edges to be (possibly) instrumented. */
+
+ for (i = 0; i < n_basic_blocks + 2; i++)
+ {
+ basic_block bb = GCOV_INDEX_TO_BB (i);
+ edge e;
+ for (e = bb->succ; e; e = e->succ_next)
+ if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
+ {
+ num_edges++;
+ }
+ }
+
+ /* now read and combine all matching profiles. */
+
+ profile = xmalloc (sizeof (gcov_type) * num_edges);
+ rewind (da_file);
+ function_name_buffer_len = strlen (current_function_name) + 1;
+ function_name_buffer = xmalloc (function_name_buffer_len + 1);
+
+ for (i = 0; i < num_edges; i++)
+ profile[i] = 0;
+
+ 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;
+ }
+
+ fseek (da_file, 4 + 8, SEEK_CUR);
+
+ /* read the maximal counter. */
+ __read_gcov_type (&max_counter_in_run, da_file, 8);
+
+ /* skip the rest of "statistics" emited by __bb_exit_func. */
+ fseek (da_file, extra_bytes - (4 + 8 + 8), 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, current_function_name) != 0)
+ {
+ /* skip */
+ if (fseek (da_file, arc_count * 8, SEEK_CUR) < 0)
+ {
+ okay = 0;
+ break;
+ }
+ }
+ else if (arc_count != num_edges
+ || chksum != profile_info.current_function_cfg_checksum)
+ okay = 0, mismatch = 1;
+ else
+ {
+ gcov_type tmp;
+
+ profile_info.max_counter_in_program += max_counter_in_run;
+ profile_info.count_profiles_merged++;
+
+ 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)
+ {
+ if (mismatch)
+ error
+ ("Profile does not match flowgraph of function %s (out of date?)",
+ current_function_name);
+ else
+ error (".da file corrupted");
+ free (profile);
+ return 0;
+ }
+
+ return profile;
+}
+
+
/* Compute the branch probabilities for the various branches.
Annotate them accordingly. */
@@ -218,6 +379,8 @@ compute_branch_probabilities ()
int hist_br_prob[20];
int num_never_executed;
int num_branches;
+ gcov_type *exec_counts = get_exec_counts ();
+ int exec_counts_pos = 0;
/* Attach extra info block to each bb. */
@@ -253,14 +416,13 @@ compute_branch_probabilities ()
if (!EDGE_INFO (e)->ignore && !EDGE_INFO (e)->on_tree)
{
num_edges++;
- if (da_file)
+ if (exec_counts)
{
- gcov_type value;
- __read_gcov_type (&value, da_file, 8);
- e->count = value;
+ e->count = exec_counts[exec_counts_pos++];
}
else
e->count = 0;
+
EDGE_INFO (e)->count_valid = 1;
BB_INFO (bb)->succ_count--;
BB_INFO (e->dest)->pred_count--;
@@ -517,6 +679,36 @@ compute_branch_probabilities ()
}
free_aux_for_blocks ();
+ if (exec_counts)
+ free (exec_counts);
+}
+
+/* Compute checksum for the current function. */
+
+#define CHSUM_HASH 500000003
+#define CHSUM_SHIFT 2
+
+static long
+compute_checksum ()
+{
+ long chsum = 0;
+ int i;
+
+
+ for (i = 0; i < n_basic_blocks ; i++)
+ {
+ basic_block bb = BASIC_BLOCK (i);
+ edge e;
+
+ for (e = bb->succ; e; e = e->succ_next)
+ {
+ chsum = ((chsum << CHSUM_SHIFT) + (BB_TO_GCOV_INDEX (e->dest) + 1)) % CHSUM_HASH;
+ }
+
+ chsum = (chsum << CHSUM_SHIFT) % CHSUM_HASH;
+ }
+
+ return chsum;
}
/* Instrument and/or analyze program behavior based on program flow graph.
@@ -542,6 +734,12 @@ branch_prob ()
int num_edges, ignored_edges;
struct edge_list *el;
+ profile_info.current_function_cfg_checksum = compute_checksum ();
+
+ if (rtl_dump_file)
+ fprintf (rtl_dump_file, "CFG checksum is %ld\n",
+ profile_info.current_function_cfg_checksum);
+
/* Start of a function. */
if (flag_test_coverage)
output_gcov_string (current_function_name, (long) -2);
@@ -758,6 +956,12 @@ branch_prob ()
{
int flag_bits;
+ __write_gcov_string (current_function_name,
+ strlen (current_function_name), bbg_file, -1);
+
+ /* write checksum. */
+ __write_long (profile_info.current_function_cfg_checksum, bbg_file, 4);
+
/* The plus 2 stands for entry and exit block. */
__write_long (n_basic_blocks + 2, bbg_file, 4);
__write_long (num_edges - ignored_edges + 1, bbg_file, 4);
@@ -884,14 +1088,21 @@ find_spanning_tree (el)
/* Add fake edge exit to entry we can't instrument. */
union_groups (EXIT_BLOCK_PTR, ENTRY_BLOCK_PTR);
- /* First add all abnormal edges to the tree unless they form an cycle. */
+ /* First add all abnormal edges to the tree unless they form an cycle. Also
+ add all edges to EXIT_BLOCK_PTR to avoid inserting profiling code behind
+ setting return value from function. */
for (i = 0; i < num_edges; i++)
{
edge e = INDEX_EDGE (el, i);
- if ((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_FAKE))
+ if (((e->flags & (EDGE_ABNORMAL | EDGE_ABNORMAL_CALL | EDGE_FAKE))
+ || e->dest == EXIT_BLOCK_PTR
+ )
&& !EDGE_INFO (e)->ignore
&& (find_group (e->src) != find_group (e->dest)))
{
+ if (rtl_dump_file)
+ fprintf (rtl_dump_file, "Abnormal edge %d to %d put to tree\n",
+ e->src->index, e->dest->index);
EDGE_INFO (e)->on_tree = 1;
union_groups (e->src, e->dest);
}
@@ -905,6 +1116,9 @@ find_spanning_tree (el)
&& !EDGE_INFO (e)->ignore
&& (find_group (e->src) != find_group (e->dest)))
{
+ if (rtl_dump_file)
+ fprintf (rtl_dump_file, "Critical edge %d to %d put to tree\n",
+ e->src->index, e->dest->index);
EDGE_INFO (e)->on_tree = 1;
union_groups (e->src, e->dest);
}
@@ -917,6 +1131,9 @@ find_spanning_tree (el)
if (find_group (e->src) != find_group (e->dest)
&& !EDGE_INFO (e)->ignore)
{
+ if (rtl_dump_file)
+ fprintf (rtl_dump_file, "Normal edge %d to %d put to tree\n",
+ e->src->index, e->dest->index);
EDGE_INFO (e)->on_tree = 1;
union_groups (e->src, e->dest);
}
@@ -975,12 +1192,6 @@ init_branch_prob (filename)
if ((da_file = fopen (da_file_name, "rb")) == 0)
warning ("file %s not found, execution counts assumed to be zero",
da_file_name);
-
- /* The first word in the .da file gives the number of instrumented
- edges, which is not needed for our purposes. */
-
- if (da_file)
- __read_long (&len, da_file, 8);
}
if (profile_arc_flag)
@@ -1011,22 +1222,8 @@ end_branch_prob ()
fclose (bbg_file);
}
- if (flag_branch_probabilities)
- {
- if (da_file)
- {
- long temp;
- /* This seems slightly dangerous, as it presumes the EOF
- flag will not be set until an attempt is made to read
- past the end of the file. */
- if (feof (da_file))
- error (".da file contents exhausted too early");
- /* Should be at end of file now. */
- if (__read_long (&temp, da_file, 8) == 0)
- error (".da file contents not exhausted");
- fclose (da_file);
- }
- }
+ if (flag_branch_probabilities && da_file)
+ fclose (da_file);
if (rtl_dump_file)
{
@@ -1097,6 +1294,8 @@ gen_edge_profiler (edgeno)
tmp = expand_simple_binop (mode, PLUS, mem_ref, const1_rtx,
mem_ref, 0, OPTAB_WIDEN);
+ set_mem_alias_set (mem_ref, new_alias_set ());
+
if (tmp != mem_ref)
emit_move_insn (copy_rtx (mem_ref), tmp);
@@ -1118,9 +1317,6 @@ output_func_start_profiler ()
rtx table_address;
enum machine_mode mode = mode_for_size (GCOV_TYPE_SIZE, MODE_INT, 0);
int save_flag_inline_functions = flag_inline_functions;
- int save_flag_test_coverage = flag_test_coverage;
- int save_profile_arc_flag = profile_arc_flag;
- int save_flag_branch_probabilities = flag_branch_probabilities;
/* It's either already been output, or we don't need it because we're
not doing profile-edges. */
@@ -1163,6 +1359,7 @@ output_func_start_profiler ()
init_function_start (fndecl, input_filename, lineno);
(*lang_hooks.decls.pushlevel) (0);
expand_function_start (fndecl, 0);
+ cfun->arc_profile = 0;
/* Actually generate the code to call __bb_init_func. */
ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 0);
@@ -1179,20 +1376,10 @@ output_func_start_profiler ()
flag_inline_functions. */
flag_inline_functions = 0;
- /* Don't instrument the function that turns on instrumentation. Which
- is also handy since we'd get silly warnings about not consuming all
- of our da_file input. */
- flag_test_coverage = 0;
- profile_arc_flag = 0;
- flag_branch_probabilities = 0;
-
rest_of_compilation (fndecl);
/* Reset flag_inline_functions to its original value. */
flag_inline_functions = save_flag_inline_functions;
- flag_test_coverage = save_flag_test_coverage;
- profile_arc_flag = save_profile_arc_flag;
- flag_branch_probabilities = save_flag_branch_probabilities;
if (! quiet_flag)
fflush (asm_out_file);