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 <bim@atrey.karlin.mff.cuni.cz> From-SVN: r53326
This commit is contained in:
parent
786de7eb9a
commit
b7c9bf289f
12 changed files with 994 additions and 300 deletions
|
@ -1,3 +1,42 @@
|
|||
Thu May 9 14:52:45 CEST 2002 Jan Hubicka <jh@suse.cz>
|
||||
Pavel Nejedly <bim@atrey.karlin.mff.cuni.cz>
|
||||
|
||||
* 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.
|
||||
|
||||
2002-05-09 Kazu Hirata <kazu@cs.umass.edu>
|
||||
|
||||
* sbitmap.c: Fix formatting.
|
||||
|
|
|
@ -1484,7 +1484,7 @@ conflict.o : conflict.c $(CONFIG_H) $(SYSTEM_H) $(OBSTACK_H) $(HASHTAB_H) \
|
|||
profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
|
||||
insn-config.h output.h $(REGS_H) $(EXPR_H) function.h \
|
||||
gcov-io.h toplev.h $(GGC_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TARGET_H) \
|
||||
langhooks.h
|
||||
langhooks.h profile.h libfuncs.h
|
||||
loop.o : loop.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) flags.h $(LOOP_H) \
|
||||
insn-config.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) \
|
||||
real.h $(PREDICT_H) $(BASIC_BLOCK_H) function.h \
|
||||
|
@ -1568,7 +1568,7 @@ sched-vis.o : sched-vis.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) sched-int.h \
|
|||
$(TARGET_H) real.h
|
||||
final.o : final.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h intl.h \
|
||||
$(REGS_H) $(RECOG_H) conditions.h insn-config.h $(INSN_ATTR_H) function.h \
|
||||
real.h output.h hard-reg-set.h except.h debug.h xcoffout.h \
|
||||
real.h output.h hard-reg-set.h except.h debug.h xcoffout.h profile.h \
|
||||
toplev.h reload.h dwarf2out.h $(BASIC_BLOCK_H) $(TM_P_H) $(TARGET_H) $(EXPR_H)
|
||||
recog.o : recog.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) function.h $(BASIC_BLOCK_H) \
|
||||
$(REGS_H) $(RECOG_H) $(EXPR_H) hard-reg-set.h flags.h insn-config.h \
|
||||
|
|
|
@ -363,6 +363,8 @@ program flow.
|
|||
|
||||
In the @file{.bbg} file, the format is:
|
||||
@smallexample
|
||||
name of function #0
|
||||
checksum of function #0
|
||||
number of basic blocks for function #0 (4-byte number)
|
||||
total number of arcs for function #0 (4-byte number)
|
||||
count of arcs in basic block #0 (4-byte number)
|
||||
|
@ -383,6 +385,9 @@ A @minus{}1 (stored as a 4-byte number) is used to separate each function's
|
|||
list of basic blocks, and to verify that the file has been read
|
||||
correctly.
|
||||
|
||||
The function name is stored as a @minus{}1 (4 bytes), the length (4 bytes),
|
||||
the name itself (padded to 4-byte boundary) followed by a @minus{}1 (4 bytes).
|
||||
|
||||
The @file{.da} file is generated when a program containing object files
|
||||
built with the GCC @option{-fprofile-arcs} option is executed. A
|
||||
separate @file{.da} file is created for each source file compiled with
|
||||
|
@ -390,15 +395,32 @@ this option, and the name of the @file{.da} file is stored as an
|
|||
absolute pathname in the resulting object file. This path name is
|
||||
derived from the source file name by substituting a @file{.da} suffix.
|
||||
|
||||
The format of the @file{.da} file is fairly simple. The first 8-byte
|
||||
number is the number of counts in the file, followed by the counts
|
||||
(stored as 8-byte numbers). Each count corresponds to the number of
|
||||
times each arc in the program is executed. The counts are cumulative;
|
||||
each time the program is executed, it attempts to combine the existing
|
||||
@file{.da} files with the new counts for this invocation of the
|
||||
program. It ignores the contents of any @file{.da} files whose number of
|
||||
arcs doesn't correspond to the current program, and merely overwrites
|
||||
them instead.
|
||||
The @file{.da} consists of several blocks (one for each run) with the following structure:
|
||||
@smallexample
|
||||
"magic" number @minus{}123 (4-byte number)
|
||||
number of functions (4-byte number)
|
||||
length of the "extension block" in bytes
|
||||
extension block (variable length)
|
||||
name of function #0 (the same format as in .bbg file)
|
||||
checksum of function #0
|
||||
number of instrumented arcs (4-byte number)
|
||||
count of arc #0 (8-byte number)
|
||||
count of arc #1 (8-byte number)
|
||||
@dots{}
|
||||
count of arc #M_0 (8-byte number)
|
||||
name of function #1 (the same format as in .bbg file)
|
||||
checksum of function #1
|
||||
@dots{}
|
||||
@end smallexample
|
||||
The current structure of the extension block is as follows:
|
||||
@smallexample
|
||||
number of instrumented arcs in whole program (4-byte number)
|
||||
sum all of instrumented arcs in whole program (8-byte number)
|
||||
maximal value of counter in whole program (8-byte number)
|
||||
number of instrumented arcs in the object file (4-byte number)
|
||||
sum all of instrumented arcs in the object file (8-byte number)
|
||||
maximal value of counter in the object file (8-byte number)
|
||||
@end smallexample
|
||||
|
||||
All three of these files use the functions in @file{gcov-io.h} to store
|
||||
integers; the functions in this header provide a machine-independent
|
||||
|
|
391
gcc/final.c
391
gcc/final.c
|
@ -68,6 +68,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|||
#include "target.h"
|
||||
#include "debug.h"
|
||||
#include "expr.h"
|
||||
#include "profile.h"
|
||||
|
||||
#ifdef XCOFF_DEBUGGING_INFO
|
||||
#include "xcoffout.h" /* Needed for external data
|
||||
|
@ -114,9 +115,6 @@ static int high_function_linenum;
|
|||
/* Filename of last NOTE. */
|
||||
static const char *last_filename;
|
||||
|
||||
/* Number of instrumented arcs when profile_arc_flag is set. */
|
||||
extern int count_instrumented_edges;
|
||||
|
||||
extern int length_unit_log; /* This is defined in insn-attrtab.c. */
|
||||
|
||||
/* Nonzero while outputting an `asm' with operands.
|
||||
|
@ -198,6 +196,17 @@ static char *line_note_exists;
|
|||
rtx current_insn_predicate;
|
||||
#endif
|
||||
|
||||
struct function_list
|
||||
{
|
||||
struct function_list *next; /* next function */
|
||||
const char *name; /* function name */
|
||||
long cfg_checksum; /* function checksum */
|
||||
long count_edges; /* number of intrumented edges in this function */
|
||||
};
|
||||
|
||||
static struct function_list *functions_head = 0;
|
||||
static struct function_list **functions_tail = &functions_head;
|
||||
|
||||
#ifdef HAVE_ATTR_length
|
||||
static int asm_insn_count PARAMS ((rtx));
|
||||
#endif
|
||||
|
@ -237,7 +246,7 @@ init_final (filename)
|
|||
}
|
||||
|
||||
/* Called at end of source file,
|
||||
to output the block-profiling table for this entire compilation. */
|
||||
to output the arc-profiling table for this entire compilation. */
|
||||
|
||||
void
|
||||
end_final (filename)
|
||||
|
@ -246,128 +255,268 @@ end_final (filename)
|
|||
if (profile_arc_flag)
|
||||
{
|
||||
char name[20];
|
||||
int align = exact_log2 (BIGGEST_ALIGNMENT / BITS_PER_UNIT);
|
||||
int size, rounded;
|
||||
int long_bytes = LONG_TYPE_SIZE / BITS_PER_UNIT;
|
||||
int gcov_type_bytes = GCOV_TYPE_SIZE / BITS_PER_UNIT;
|
||||
int pointer_bytes = POINTER_SIZE / BITS_PER_UNIT;
|
||||
unsigned int align2 = LONG_TYPE_SIZE;
|
||||
tree string_type, string_cst;
|
||||
tree structure_decl, structure_value, structure_pointer_type;
|
||||
tree field_decl, decl_chain, value_chain;
|
||||
tree nwords_field_value, domain_type;
|
||||
|
||||
size = gcov_type_bytes * count_instrumented_edges;
|
||||
rounded = size;
|
||||
/* Build types. */
|
||||
string_type = build_pointer_type (char_type_node);
|
||||
|
||||
rounded += (BIGGEST_ALIGNMENT / BITS_PER_UNIT) - 1;
|
||||
rounded = (rounded / (BIGGEST_ALIGNMENT / BITS_PER_UNIT)
|
||||
* (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
|
||||
/* Libgcc2 bb structure. */
|
||||
structure_decl = make_node (RECORD_TYPE);
|
||||
TYPE_PACKED (structure_decl) = flag_pack_struct;
|
||||
structure_pointer_type = build_pointer_type (structure_decl);
|
||||
|
||||
/* ??? This _really_ ought to be done with a structure layout
|
||||
and with assemble_constructor. If long_bytes != pointer_bytes
|
||||
we'll be emitting unaligned data at some point. */
|
||||
if (long_bytes != pointer_bytes)
|
||||
abort ();
|
||||
|
||||
data_section ();
|
||||
|
||||
/* Output the main header, of 11 words:
|
||||
0: 1 if this file is initialized, else 0.
|
||||
1: address of file name (LPBX1).
|
||||
2: address of table of counts (LPBX2).
|
||||
3: number of counts in the table.
|
||||
4: always 0, for compatibility with Sun.
|
||||
/* Output the main header, of 7 words:
|
||||
0: 1 if this file is initialized, else 0.
|
||||
1: address of file name (LPBX1).
|
||||
2: address of table of counts (LPBX2).
|
||||
3: number of counts in the table.
|
||||
4: always 0, libgcc2 uses this as a pointer to next ``struct bb''
|
||||
|
||||
The following are GNU extensions:
|
||||
|
||||
5: address of table of start addrs of basic blocks (LPBX3).
|
||||
6: Number of bytes in this header.
|
||||
7: address of table of function names (LPBX4).
|
||||
8: address of table of line numbers (LPBX5) or 0.
|
||||
9: address of table of file names (LPBX6) or 0.
|
||||
10: space reserved for basic block profiling. */
|
||||
5: Number of bytes in this header.
|
||||
6: address of table of function checksums (LPBX7). */
|
||||
|
||||
ASM_OUTPUT_ALIGN (asm_out_file, align);
|
||||
|
||||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 0);
|
||||
|
||||
/* Zero word. */
|
||||
assemble_integer (const0_rtx, long_bytes, align2, 1);
|
||||
/* The zero word. */
|
||||
decl_chain =
|
||||
build_decl (FIELD_DECL, get_identifier ("zero_word"),
|
||||
long_integer_type_node);
|
||||
value_chain = build_tree_list (decl_chain, integer_zero_node);
|
||||
|
||||
/* Address of filename. */
|
||||
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 1);
|
||||
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
|
||||
align2, 1);
|
||||
|
||||
/* Address of count table. */
|
||||
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
|
||||
assemble_integer (gen_rtx_SYMBOL_REF (Pmode, name), pointer_bytes,
|
||||
align2, 1);
|
||||
|
||||
/* Count of the # of instrumented arcs. */
|
||||
assemble_integer (GEN_INT (count_instrumented_edges),
|
||||
long_bytes, align2, 1);
|
||||
|
||||
/* Zero word (link field). */
|
||||
assemble_integer (const0_rtx, pointer_bytes, align2, 1);
|
||||
|
||||
assemble_integer (const0_rtx, pointer_bytes, align2, 1);
|
||||
|
||||
/* Byte count for extended structure. */
|
||||
assemble_integer (GEN_INT (11 * UNITS_PER_WORD), long_bytes, align2, 1);
|
||||
|
||||
/* Address of function name table. */
|
||||
assemble_integer (const0_rtx, pointer_bytes, align2, 1);
|
||||
|
||||
/* Address of line number and filename tables if debugging. */
|
||||
assemble_integer (const0_rtx, pointer_bytes, align2, 1);
|
||||
assemble_integer (const0_rtx, pointer_bytes, align2, 1);
|
||||
|
||||
/* Space for extension ptr (link field). */
|
||||
assemble_integer (const0_rtx, UNITS_PER_WORD, align2, 1);
|
||||
|
||||
/* Output the file name changing the suffix to .d for
|
||||
Sun tcov compatibility. */
|
||||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 1);
|
||||
{
|
||||
char *cwd = getpwd ();
|
||||
int len = strlen (filename) + strlen (cwd) + 1;
|
||||
char *data_file = (char *) alloca (len + 4);
|
||||
int da_filename_len = strlen (filename) + strlen (cwd) + 4 + 1;
|
||||
char *da_filename = (char *) alloca (da_filename_len);
|
||||
|
||||
strcpy (data_file, cwd);
|
||||
strcat (data_file, "/");
|
||||
strcat (data_file, filename);
|
||||
strip_off_ending (data_file, len);
|
||||
strcat (data_file, ".da");
|
||||
assemble_string (data_file, strlen (data_file) + 1);
|
||||
strcpy (da_filename, cwd);
|
||||
strcat (da_filename, "/");
|
||||
strcat (da_filename, filename);
|
||||
strip_off_ending (da_filename, da_filename_len - 3);
|
||||
strcat (da_filename, ".da");
|
||||
field_decl =
|
||||
build_decl (FIELD_DECL, get_identifier ("filename"), string_type);
|
||||
string_cst = build_string (strlen (da_filename) + 1, da_filename);
|
||||
domain_type = build_index_type (build_int_2 (strlen (da_filename) + 1,
|
||||
0));
|
||||
TREE_TYPE (string_cst) =
|
||||
build_array_type (char_type_node, domain_type);
|
||||
value_chain = tree_cons (field_decl,
|
||||
build1 (ADDR_EXPR, string_type, string_cst),
|
||||
value_chain);
|
||||
TREE_CHAIN (field_decl) = decl_chain;
|
||||
decl_chain = field_decl;
|
||||
}
|
||||
|
||||
/* Make space for the table of counts. */
|
||||
if (size == 0)
|
||||
{
|
||||
/* Realign data section. */
|
||||
ASM_OUTPUT_ALIGN (asm_out_file, align);
|
||||
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "LPBX", 2);
|
||||
if (size != 0)
|
||||
assemble_zeros (size);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
|
||||
#ifdef ASM_OUTPUT_SHARED_LOCAL
|
||||
if (flag_shared_data)
|
||||
ASM_OUTPUT_SHARED_LOCAL (asm_out_file, name, size, rounded);
|
||||
else
|
||||
#endif
|
||||
#ifdef ASM_OUTPUT_ALIGNED_DECL_LOCAL
|
||||
ASM_OUTPUT_ALIGNED_DECL_LOCAL (asm_out_file, NULL_TREE, name,
|
||||
size, BIGGEST_ALIGNMENT);
|
||||
#else
|
||||
#ifdef ASM_OUTPUT_ALIGNED_LOCAL
|
||||
ASM_OUTPUT_ALIGNED_LOCAL (asm_out_file, name, size,
|
||||
BIGGEST_ALIGNMENT);
|
||||
#else
|
||||
ASM_OUTPUT_LOCAL (asm_out_file, name, size, rounded);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
/* Table of counts. */
|
||||
{
|
||||
tree gcov_type_type = make_unsigned_type (GCOV_TYPE_SIZE);
|
||||
tree gcov_type_pointer_type = build_pointer_type (gcov_type_type);
|
||||
tree gcov_type_array_type, gcov_type_array_pointer_type;
|
||||
tree domain_tree = build_index_type (build_int_2
|
||||
(profile_info.
|
||||
count_instrumented_edges - 1,
|
||||
0));
|
||||
tree counts_table;
|
||||
|
||||
gcov_type_array_type = build_array_type (gcov_type_type, domain_tree);
|
||||
gcov_type_array_pointer_type =
|
||||
build_pointer_type (gcov_type_array_type);
|
||||
|
||||
/* No values. */
|
||||
counts_table =
|
||||
build (VAR_DECL, gcov_type_array_type, NULL_TREE, NULL_TREE);
|
||||
TREE_STATIC (counts_table) = 1;
|
||||
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 2);
|
||||
DECL_NAME (counts_table) = get_identifier (name);
|
||||
assemble_variable (counts_table, 0, 0, 0);
|
||||
|
||||
field_decl =
|
||||
build_decl (FIELD_DECL, get_identifier ("counts"),
|
||||
gcov_type_pointer_type);
|
||||
value_chain = tree_cons (field_decl,
|
||||
build1 (ADDR_EXPR,
|
||||
gcov_type_array_pointer_type,
|
||||
counts_table), value_chain);
|
||||
TREE_CHAIN (field_decl) = decl_chain;
|
||||
decl_chain = field_decl;
|
||||
}
|
||||
|
||||
/* Count of the # of instrumented arcs. */
|
||||
field_decl =
|
||||
build_decl (FIELD_DECL, get_identifier ("ncounts"),
|
||||
long_integer_type_node);
|
||||
value_chain = tree_cons (field_decl,
|
||||
convert (long_integer_type_node,
|
||||
build_int_2 (profile_info.
|
||||
count_instrumented_edges,
|
||||
0)), value_chain);
|
||||
TREE_CHAIN (field_decl) = decl_chain;
|
||||
decl_chain = field_decl;
|
||||
|
||||
/* Pointer to the next bb. */
|
||||
field_decl =
|
||||
build_decl (FIELD_DECL, get_identifier ("next"),
|
||||
structure_pointer_type);
|
||||
value_chain = tree_cons (field_decl, null_pointer_node, value_chain);
|
||||
TREE_CHAIN (field_decl) = decl_chain;
|
||||
decl_chain = field_decl;
|
||||
|
||||
/* Number of words. We'll set this after entire structure is laid out. */
|
||||
field_decl =
|
||||
build_decl (FIELD_DECL, get_identifier ("nwords"),
|
||||
long_integer_type_node);
|
||||
value_chain = nwords_field_value =
|
||||
tree_cons (field_decl, NULL, value_chain);
|
||||
TREE_CHAIN (field_decl) = decl_chain;
|
||||
decl_chain = field_decl;
|
||||
|
||||
/* struct bb_function []. */
|
||||
{
|
||||
struct function_list *item;
|
||||
int num_nodes;
|
||||
tree checksum_field, arc_count_field, name_field;
|
||||
tree domain;
|
||||
tree array_value_chain = NULL_TREE;
|
||||
tree bb_fn_struct_type;
|
||||
tree bb_fn_struct_array_type;
|
||||
tree bb_fn_struct_array_pointer_type;
|
||||
tree bb_fn_struct_pointer_type;
|
||||
tree field_value, field_value_chain;
|
||||
|
||||
bb_fn_struct_type = make_node (RECORD_TYPE);
|
||||
TYPE_PACKED (bb_fn_struct_type) = flag_pack_struct;
|
||||
|
||||
checksum_field = build_decl (FIELD_DECL, get_identifier ("checksum"),
|
||||
long_integer_type_node);
|
||||
arc_count_field =
|
||||
build_decl (FIELD_DECL, get_identifier ("arc_count"),
|
||||
integer_type_node);
|
||||
TREE_CHAIN (checksum_field) = arc_count_field;
|
||||
name_field =
|
||||
build_decl (FIELD_DECL, get_identifier ("name"), string_type);
|
||||
TREE_CHAIN (arc_count_field) = name_field;
|
||||
|
||||
TYPE_FIELDS (bb_fn_struct_type) = checksum_field;
|
||||
|
||||
num_nodes = 0;
|
||||
|
||||
for (item = functions_head; item != 0; item = item->next)
|
||||
num_nodes++;
|
||||
|
||||
/* Note that the array contains a terminator, hence no - 1. */
|
||||
domain = build_index_type (build_int_2 (num_nodes, 0));
|
||||
|
||||
bb_fn_struct_pointer_type = build_pointer_type (bb_fn_struct_type);
|
||||
bb_fn_struct_array_type = build_array_type (bb_fn_struct_type,
|
||||
domain);
|
||||
bb_fn_struct_array_pointer_type =
|
||||
build_pointer_type (bb_fn_struct_array_type);
|
||||
|
||||
layout_type (bb_fn_struct_type);
|
||||
layout_type (bb_fn_struct_pointer_type);
|
||||
layout_type (bb_fn_struct_array_type);
|
||||
layout_type (bb_fn_struct_array_pointer_type);
|
||||
|
||||
for (item = functions_head; item != 0; item = item->next)
|
||||
{
|
||||
/* create constructor for structure. */
|
||||
field_value_chain = build_tree_list (checksum_field,
|
||||
convert
|
||||
(long_integer_type_node,
|
||||
build_int_2 (item->
|
||||
cfg_checksum,
|
||||
0)));
|
||||
field_value_chain =
|
||||
tree_cons (arc_count_field,
|
||||
convert (integer_type_node,
|
||||
build_int_2 (item->count_edges, 0)),
|
||||
field_value_chain);
|
||||
|
||||
string_cst = build_string (strlen (item->name) + 1, item->name);
|
||||
domain_type = build_index_type (build_int_2 (strlen (item->name) +
|
||||
1, 0));
|
||||
TREE_TYPE (string_cst) = build_array_type (char_type_node,
|
||||
domain_type);
|
||||
field_value_chain = tree_cons (name_field,
|
||||
build1 (ADDR_EXPR, string_type,
|
||||
string_cst),
|
||||
field_value_chain);
|
||||
|
||||
/* Add to chain. */
|
||||
|
||||
array_value_chain = tree_cons (NULL_TREE,
|
||||
build (CONSTRUCTOR,
|
||||
bb_fn_struct_type,
|
||||
NULL_TREE,
|
||||
nreverse
|
||||
(field_value_chain)),
|
||||
array_value_chain);
|
||||
}
|
||||
|
||||
/* Add terminator. */
|
||||
field_value = build_tree_list (arc_count_field,
|
||||
convert (integer_type_node,
|
||||
build_int_2 (-1, 0)));
|
||||
|
||||
array_value_chain = tree_cons (NULL_TREE,
|
||||
build (CONSTRUCTOR, bb_fn_struct_type,
|
||||
NULL_TREE, field_value),
|
||||
array_value_chain);
|
||||
|
||||
|
||||
/* Create constructor for array. */
|
||||
|
||||
field_decl =
|
||||
build_decl (FIELD_DECL, get_identifier ("function_infos"),
|
||||
bb_fn_struct_pointer_type);
|
||||
value_chain = tree_cons (field_decl,
|
||||
build1 (ADDR_EXPR,
|
||||
bb_fn_struct_array_pointer_type,
|
||||
build (CONSTRUCTOR,
|
||||
bb_fn_struct_array_type,
|
||||
NULL_TREE,
|
||||
nreverse
|
||||
(array_value_chain))),
|
||||
value_chain);
|
||||
TREE_CHAIN (field_decl) = decl_chain;
|
||||
decl_chain = field_decl;
|
||||
}
|
||||
|
||||
|
||||
/* Finish structure. */
|
||||
TYPE_FIELDS (structure_decl) = nreverse (decl_chain);
|
||||
layout_type (structure_decl);
|
||||
|
||||
structure_value =
|
||||
build (VAR_DECL, structure_decl, NULL_TREE, NULL_TREE);
|
||||
DECL_INITIAL (structure_value) =
|
||||
build (CONSTRUCTOR, structure_decl, NULL_TREE,
|
||||
nreverse (value_chain));
|
||||
TREE_STATIC (structure_value) = 1;
|
||||
ASM_GENERATE_INTERNAL_LABEL (name, "LPBX", 0);
|
||||
DECL_NAME (structure_value) = get_identifier (name);
|
||||
|
||||
/* Set number of words in this structure. */
|
||||
TREE_VALUE (nwords_field_value) =
|
||||
build_int_2 (TREE_INT_CST_LOW (TYPE_SIZE_UNIT (structure_decl)) /
|
||||
(INT_TYPE_SIZE / BITS_PER_UNIT), 0);
|
||||
|
||||
/* Build structure. */
|
||||
assemble_variable (structure_value, 0, 0, 0);
|
||||
|
||||
/* Offset to table of arc counters for thread-safe profiling. */
|
||||
{
|
||||
tree table_offset_var = make_node (VAR_DECL);
|
||||
TREE_TYPE (table_offset_var) = build_pointer_type (integer_type_node);
|
||||
DECL_INITIAL (table_offset_var) = integer_zero_node;
|
||||
DECL_NAME (table_offset_var) = get_identifier (".LPBF0");
|
||||
TREE_STATIC (table_offset_var) = 1;
|
||||
assemble_variable (table_offset_var, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1781,6 +1930,24 @@ final (first, file, optimize, prescan)
|
|||
insn = final_scan_insn (insn, file, optimize, prescan, 0);
|
||||
}
|
||||
|
||||
/* Store function names for edge-profiling. */
|
||||
|
||||
if (profile_arc_flag)
|
||||
{
|
||||
struct function_list *new_item = xmalloc (sizeof (struct function_list));
|
||||
|
||||
/* Add function to linked list. */
|
||||
new_item->next = 0;
|
||||
*functions_tail = new_item;
|
||||
functions_tail = &new_item->next;
|
||||
|
||||
/* Set values. */
|
||||
new_item->cfg_checksum = profile_info.current_function_cfg_checksum;
|
||||
new_item->count_edges = profile_info.count_edges_instrumented_now;
|
||||
new_item->name = xstrdup (current_function_name);
|
||||
|
||||
}
|
||||
|
||||
free (line_note_exists);
|
||||
line_note_exists = NULL;
|
||||
}
|
||||
|
|
|
@ -6318,6 +6318,8 @@ prepare_function_start ()
|
|||
|
||||
current_function_outgoing_args_size = 0;
|
||||
|
||||
cfun->arc_profile = profile_arc_flag || flag_test_coverage;
|
||||
|
||||
(*lang_hooks.function.init) (cfun);
|
||||
if (init_machine_status)
|
||||
(*init_machine_status) (cfun);
|
||||
|
|
|
@ -437,6 +437,9 @@ struct function
|
|||
generated. */
|
||||
unsigned int instrument_entry_exit : 1;
|
||||
|
||||
/* Nonzero if no profiling should be done for the function. */
|
||||
unsigned int arc_profile : 1;
|
||||
|
||||
/* Nonzero if profiling code should be generated. */
|
||||
unsigned int profile : 1;
|
||||
|
||||
|
|
115
gcc/gcov-io.h
115
gcc/gcov-io.h
|
@ -24,13 +24,24 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
|||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
static int __fetch_long PARAMS ((long *, char *, size_t)) ATTRIBUTE_UNUSED;
|
||||
static int __read_long PARAMS ((long *, FILE *, size_t)) ATTRIBUTE_UNUSED;
|
||||
static int __write_long PARAMS ((long, FILE *, size_t)) ATTRIBUTE_UNUSED;
|
||||
static int __fetch_gcov_type PARAMS ((gcov_type *, char *, size_t)) ATTRIBUTE_UNUSED;
|
||||
static int __store_gcov_type PARAMS ((gcov_type, char *, size_t)) ATTRIBUTE_UNUSED;
|
||||
static int __read_gcov_type PARAMS ((gcov_type *, FILE *, size_t)) ATTRIBUTE_UNUSED;
|
||||
static int __write_gcov_type PARAMS ((gcov_type, FILE *, size_t)) ATTRIBUTE_UNUSED;
|
||||
static int __fetch_long PARAMS ((long *, char *, size_t))
|
||||
ATTRIBUTE_UNUSED;
|
||||
static int __read_long PARAMS ((long *, FILE *, size_t))
|
||||
ATTRIBUTE_UNUSED;
|
||||
static int __write_long PARAMS ((long, FILE *, size_t))
|
||||
ATTRIBUTE_UNUSED;
|
||||
static int __fetch_gcov_type PARAMS ((gcov_type *, char *, size_t))
|
||||
ATTRIBUTE_UNUSED;
|
||||
static int __store_gcov_type PARAMS ((gcov_type, char *, size_t))
|
||||
ATTRIBUTE_UNUSED;
|
||||
static int __read_gcov_type PARAMS ((gcov_type *, FILE *, size_t))
|
||||
ATTRIBUTE_UNUSED;
|
||||
static int __write_gcov_type PARAMS ((gcov_type, FILE *, size_t))
|
||||
ATTRIBUTE_UNUSED;
|
||||
static int __write_gcov_string PARAMS ((const char *, size_t, FILE*, long))
|
||||
ATTRIBUTE_UNUSED;
|
||||
static int __read_gcov_string PARAMS ((char *, size_t, FILE*, long))
|
||||
ATTRIBUTE_UNUSED;
|
||||
|
||||
/* These routines only work for signed values. */
|
||||
|
||||
|
@ -193,4 +204,94 @@ __read_long (dest, file, bytes)
|
|||
return __fetch_long (dest, c, bytes);
|
||||
}
|
||||
|
||||
|
||||
/* Writes string in gcov format. */
|
||||
|
||||
static int
|
||||
__write_gcov_string (string, length, file, delim)
|
||||
const char *string;
|
||||
size_t length;
|
||||
FILE *file;
|
||||
long delim;
|
||||
{
|
||||
size_t temp = length + 1;
|
||||
|
||||
/* delimiter */
|
||||
if (__write_long (delim, file, 4) != 0)
|
||||
return 1;
|
||||
|
||||
if (__write_long (length, file, 4) != 0)
|
||||
return 1;
|
||||
|
||||
if (fwrite (string, temp, 1, file) != 1)
|
||||
return 1;
|
||||
|
||||
temp &= 3;
|
||||
|
||||
if (temp)
|
||||
{
|
||||
char c[4];
|
||||
|
||||
c[0] = c[1] = c[2] = c[3] = 0;
|
||||
|
||||
if (fwrite (c, sizeof (char), 4 - temp, file) != 4 - temp)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (__write_long (delim, file, 4) != 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reads string in gcov format. */
|
||||
|
||||
|
||||
static int
|
||||
__read_gcov_string (string, max_length, file, delim)
|
||||
char *string;
|
||||
size_t max_length;
|
||||
FILE *file;
|
||||
long delim;
|
||||
{
|
||||
long delim_from_file;
|
||||
long length;
|
||||
long read_length;
|
||||
long tmp;
|
||||
|
||||
if (__read_long (&delim_from_file, file, 4) != 0)
|
||||
return 1;
|
||||
|
||||
if (delim_from_file != delim)
|
||||
return 1;
|
||||
|
||||
if (__read_long (&length, file, 4) != 0)
|
||||
return 1;
|
||||
|
||||
if (length > (long) max_length)
|
||||
read_length = max_length;
|
||||
else
|
||||
read_length = length;
|
||||
|
||||
tmp = (((length + 1) - 1) / 4 + 1) * 4;
|
||||
/* This is the size occupied by the string in the file */
|
||||
|
||||
if (fread (string, read_length, 1, file) != 1)
|
||||
return 1;
|
||||
|
||||
string[read_length] = 0;
|
||||
|
||||
if (fseek (file, tmp - read_length, SEEK_CUR) < 0)
|
||||
return 1;
|
||||
|
||||
if (__read_long (&delim_from_file, file, 4) != 0)
|
||||
return 1;
|
||||
|
||||
if (delim_from_file != delim)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* ! GCC_GCOV_IO_H */
|
||||
|
|
182
gcc/gcov.c
182
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. */
|
||||
|
||||
|
|
214
gcc/libgcc2.c
214
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 firstchar;
|
||||
int i;
|
||||
|
||||
/* Make sure the output file exists -
|
||||
but don't clobber exiting data. */
|
||||
if ((da_file = fopen (ptr->filename, "a")) != 0)
|
||||
fclose (da_file);
|
||||
n_counters_p += ptr->ncounts;
|
||||
|
||||
/* Need to re-open in order to be able to write from the start. */
|
||||
da_file = fopen (ptr->filename, "r+b");
|
||||
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)
|
||||
{
|
||||
gcov_type max_counter_o = 0;
|
||||
gcov_type sum_counters_o = 0;
|
||||
int i;
|
||||
|
||||
/* Calculate the per-object statistics. */
|
||||
|
||||
for (i = 0; i < ptr->ncounts; i++)
|
||||
{
|
||||
sum_counters_o += ptr->counts[i];
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n_counts; i++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
That way we can easily verify that the proper source/executable/
|
||||
data file combination is being used from gcov. */
|
||||
|
||||
if (__write_gcov_type (ptr->ncounts, da_file, 8) != 0)
|
||||
{
|
||||
|
||||
fprintf (stderr, "arc profiling: Error writing output file %s.\n",
|
||||
ptr->filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
int j;
|
||||
|
||||
struct bb_function_info *fn_info;
|
||||
gcov_type *count_ptr = ptr->counts;
|
||||
int ret = 0;
|
||||
for (j = ptr->ncounts; j > 0; j--)
|
||||
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++)
|
||||
{
|
||||
if (__write_gcov_type (*count_ptr, da_file, 8) != 0)
|
||||
/* new function. */
|
||||
if (__write_gcov_string
|
||||
(fn_info->name, strlen (fn_info->name), da_file, -1) != 0)
|
||||
{
|
||||
ret = 1;
|
||||
fprintf (stderr,
|
||||
"arc profiling: Error writing output file %s.\n",
|
||||
ptr->filename);
|
||||
break;
|
||||
}
|
||||
|
||||
if (__write_long (fn_info->checksum, da_file, 4) != 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"arc profiling: Error writing output file %s.\n",
|
||||
ptr->filename);
|
||||
break;
|
||||
}
|
||||
|
||||
if (__write_long (fn_info->arc_count, da_file, 4) != 0)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"arc profiling: Error writing output file %s.\n",
|
||||
ptr->filename);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = fn_info->arc_count; i > 0; i--, count_ptr++)
|
||||
{
|
||||
if (__write_gcov_type (*count_ptr, da_file, 8) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i) /* there was an error */
|
||||
{
|
||||
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;
|
||||
|
|
|
@ -31,9 +31,14 @@ struct bb;
|
|||
extern void __bb_exit_func (void);
|
||||
extern void __bb_init_func (struct bb *);
|
||||
extern void __bb_fork_func (void);
|
||||
extern void __bb_trace_func (void);
|
||||
extern void __bb_trace_ret (void);
|
||||
extern void __bb_init_trace_func (struct bb *, unsigned long);
|
||||
|
||||
#if LONG_TYPE_SIZE == GCOV_TYPE_SIZE
|
||||
typedef long gcov_type;
|
||||
#else
|
||||
typedef long long gcov_type;
|
||||
#endif
|
||||
|
||||
extern gcov_type *__bb_find_arc_counters (void);
|
||||
|
||||
struct exception_descriptor;
|
||||
extern short int __get_eh_table_language (struct exception_descriptor *);
|
||||
|
|
281
gcc/profile.c
281
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);
|
||||
|
|
12
gcc/toplev.c
12
gcc/toplev.c
|
@ -364,6 +364,11 @@ int profile_flag = 0;
|
|||
|
||||
int profile_arc_flag = 0;
|
||||
|
||||
/* Nonzero if we should not attempt to generate thread-safe
|
||||
code to profile program flow graph arcs. */
|
||||
|
||||
int flag_unsafe_profile_arcs = 0;
|
||||
|
||||
/* Nonzero if generating info for gcov to calculate line test coverage. */
|
||||
|
||||
int flag_test_coverage = 0;
|
||||
|
@ -1061,6 +1066,8 @@ static const lang_independent_options f_options[] =
|
|||
N_("Support synchronous non-call exceptions") },
|
||||
{"profile-arcs", &profile_arc_flag, 1,
|
||||
N_("Insert arc based program profiling code") },
|
||||
{"unsafe-profile-arcs", &flag_unsafe_profile_arcs, 1,
|
||||
N_("Avoid thread safety profiling overhead") },
|
||||
{"test-coverage", &flag_test_coverage, 1,
|
||||
N_("Create data files needed by gcov") },
|
||||
{"branch-probabilities", &flag_branch_probabilities, 1,
|
||||
|
@ -2891,14 +2898,13 @@ rest_of_compilation (decl)
|
|||
close_dump_file (DFI_cfg, print_rtl_with_bb, insns);
|
||||
|
||||
/* Do branch profiling and static profile estimation passes. */
|
||||
if (optimize > 0 || profile_arc_flag || flag_test_coverage
|
||||
|| flag_branch_probabilities)
|
||||
if (optimize > 0 || cfun->arc_profile || flag_branch_probabilities)
|
||||
{
|
||||
struct loops loops;
|
||||
|
||||
timevar_push (TV_BRANCH_PROB);
|
||||
open_dump_file (DFI_bp, decl);
|
||||
if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
|
||||
if (cfun->arc_profile || flag_branch_probabilities)
|
||||
branch_prob ();
|
||||
|
||||
/* Discover and record the loop depth at the head of each basic
|
||||
|
|
Loading…
Add table
Reference in a new issue