/* Calculate branch probabilities, and basic block execution counts.
Copyright (C) 1990, 1991, 1992, 1993, 1994, 1996, 1997, 1998, 1999,
- 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+ 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010, 2011, 2012
Free Software Foundation, Inc.
Contributed by James E. Wilson, UC Berkeley/Cygnus Support;
based on some ideas from Dain Samples of UC Berkeley.
return num_edges;
}
+#define OVERLAP_BASE 10000
+
+/* Compare the static estimated profile to the actual profile, and
+ return the "degree of overlap" measure between them.
+
+ Degree of overlap is a number between 0 and OVERLAP_BASE. It is
+ the sum of each basic block's minimum relative weights between
+ two profiles. And overlap of OVERLAP_BASE means two profiles are
+ identical. */
+
+static int
+compute_frequency_overlap (void)
+{
+ gcov_type count_total = 0, freq_total = 0;
+ int overlap = 0;
+ basic_block bb;
+
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+ {
+ count_total += bb->count;
+ freq_total += bb->frequency;
+ }
+
+ if (count_total == 0 || freq_total == 0)
+ return 0;
+
+ FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, NULL, next_bb)
+ overlap += MIN (bb->count * OVERLAP_BASE / count_total,
+ bb->frequency * OVERLAP_BASE / freq_total);
+
+ return overlap;
+}
+
/* Compute the branch probabilities for the various branches.
Annotate them accordingly.
}
}
if (dump_file)
- dump_flow_info (dump_file, dump_flags);
+ {
+ int overlap = compute_frequency_overlap ();
+ dump_flow_info (dump_file, dump_flags);
+ fprintf (dump_file, "Static profile overlap: %d.%d%%\n",
+ overlap / (OVERLAP_BASE / 100),
+ overlap % (OVERLAP_BASE / 100));
+ }
total_num_passes += passes;
if (dump_file)
}
counts_to_freqs ();
profile_status = PROFILE_READ;
+ compute_function_frequency ();
if (dump_file)
{
fprintf (dump_file, "Adding fake entry edge to bb %i\n",
bb->index);
make_edge (ENTRY_BLOCK_PTR, bb, EDGE_FAKE);
+ /* Avoid bbs that have both fake entry edge and also some
+ exit edge. One of those edges wouldn't be added to the
+ spanning tree, but we can't instrument any of them. */
+ if (have_exit_edge || need_exit_edge)
+ {
+ gimple_stmt_iterator gsi;
+ gimple first;
+ tree fndecl;
+
+ gsi = gsi_after_labels (bb);
+ gcc_checking_assert (!gsi_end_p (gsi));
+ first = gsi_stmt (gsi);
+ if (is_gimple_debug (first))
+ {
+ gsi_next_nondebug (&gsi);
+ gcc_checking_assert (!gsi_end_p (gsi));
+ first = gsi_stmt (gsi);
+ }
+ /* Don't split the bbs containing __builtin_setjmp_receiver
+ or __builtin_setjmp_dispatcher calls. These are very
+ special and don't expect anything to be inserted before
+ them. */
+ if (!is_gimple_call (first)
+ || (fndecl = gimple_call_fndecl (first)) == NULL
+ || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL
+ || (DECL_FUNCTION_CODE (fndecl) != BUILT_IN_SETJMP_RECEIVER
+ && (DECL_FUNCTION_CODE (fndecl)
+ != BUILT_IN_SETJMP_DISPATCHER)))
+ {
+ if (dump_file)
+ fprintf (dump_file, "Splitting bb %i after labels\n",
+ bb->index);
+ split_block_after_labels (bb);
+ }
+ }
}
}
lineno_checksum = coverage_compute_lineno_checksum ();
/* Write the data from which gcov can reconstruct the basic block
- graph. */
+ graph and function line numbers */
- /* Basic block flags */
- if (coverage_begin_output (lineno_checksum, cfg_checksum))
+ if (coverage_begin_function (lineno_checksum, cfg_checksum))
{
gcov_position_t offset;
+ /* Basic block flags */
offset = gcov_write_tag (GCOV_TAG_BLOCKS);
for (i = 0; i != (unsigned) (n_basic_blocks); i++)
gcov_write_unsigned (0);
gcov_write_length (offset);
- }
-
- /* Keep all basic block indexes nonnegative in the gcov output.
- Index 0 is used for entry block, last index is for exit block.
- */
- ENTRY_BLOCK_PTR->index = 1;
- EXIT_BLOCK_PTR->index = last_basic_block;
- /* Arcs */
- if (coverage_begin_output (lineno_checksum, cfg_checksum))
- {
- gcov_position_t offset;
+ /* Keep all basic block indexes nonnegative in the gcov output.
+ Index 0 is used for entry block, last index is for exit
+ block. */
+ ENTRY_BLOCK_PTR->index = 1;
+ EXIT_BLOCK_PTR->index = last_basic_block;
+ /* Arcs */
FOR_BB_BETWEEN (bb, ENTRY_BLOCK_PTR, EXIT_BLOCK_PTR, next_bb)
{
edge e;
gcov_write_length (offset);
}
- }
- /* Line numbers. */
- if (coverage_begin_output (lineno_checksum, cfg_checksum))
- {
+ ENTRY_BLOCK_PTR->index = ENTRY_BLOCK;
+ EXIT_BLOCK_PTR->index = EXIT_BLOCK;
+
+ /* Line numbers. */
/* Initialize the output. */
output_location (NULL, 0, NULL, NULL);
}
}
- ENTRY_BLOCK_PTR->index = ENTRY_BLOCK;
- EXIT_BLOCK_PTR->index = EXIT_BLOCK;
#undef BB_TO_GCOV_INDEX
if (flag_profile_values)