Commit b7c9bf28 by Jan Hubicka Committed by Jan Hubicka

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
parent 786de7eb
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> 2002-05-09 Kazu Hirata <kazu@cs.umass.edu>
* sbitmap.c: Fix formatting. * sbitmap.c: Fix formatting.
......
...@@ -1484,7 +1484,7 @@ conflict.o : conflict.c $(CONFIG_H) $(SYSTEM_H) $(OBSTACK_H) $(HASHTAB_H) \ ...@@ -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 \ 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 \ 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) \ 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) \ 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) \ insn-config.h $(REGS_H) hard-reg-set.h $(RECOG_H) $(EXPR_H) \
real.h $(PREDICT_H) $(BASIC_BLOCK_H) function.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 \ ...@@ -1568,7 +1568,7 @@ sched-vis.o : sched-vis.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) sched-int.h \
$(TARGET_H) real.h $(TARGET_H) real.h
final.o : final.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h intl.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 \ $(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) 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) \ 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 \ $(REGS_H) $(RECOG_H) $(EXPR_H) hard-reg-set.h flags.h insn-config.h \
......
...@@ -363,6 +363,8 @@ program flow. ...@@ -363,6 +363,8 @@ program flow.
In the @file{.bbg} file, the format is: In the @file{.bbg} file, the format is:
@smallexample @smallexample
name of function #0
checksum of function #0
number of basic blocks for function #0 (4-byte number) number of basic blocks for function #0 (4-byte number)
total number of arcs 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) 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 ...@@ -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 list of basic blocks, and to verify that the file has been read
correctly. 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 The @file{.da} file is generated when a program containing object files
built with the GCC @option{-fprofile-arcs} option is executed. A built with the GCC @option{-fprofile-arcs} option is executed. A
separate @file{.da} file is created for each source file compiled with 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 ...@@ -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 absolute pathname in the resulting object file. This path name is
derived from the source file name by substituting a @file{.da} suffix. 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 The @file{.da} consists of several blocks (one for each run) with the following structure:
number is the number of counts in the file, followed by the counts @smallexample
(stored as 8-byte numbers). Each count corresponds to the number of "magic" number @minus{}123 (4-byte number)
times each arc in the program is executed. The counts are cumulative; number of functions (4-byte number)
each time the program is executed, it attempts to combine the existing length of the "extension block" in bytes
@file{.da} files with the new counts for this invocation of the extension block (variable length)
program. It ignores the contents of any @file{.da} files whose number of name of function #0 (the same format as in .bbg file)
arcs doesn't correspond to the current program, and merely overwrites checksum of function #0
them instead. 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 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 integers; the functions in this header provide a machine-independent
......
...@@ -6318,6 +6318,8 @@ prepare_function_start () ...@@ -6318,6 +6318,8 @@ prepare_function_start ()
current_function_outgoing_args_size = 0; current_function_outgoing_args_size = 0;
cfun->arc_profile = profile_arc_flag || flag_test_coverage;
(*lang_hooks.function.init) (cfun); (*lang_hooks.function.init) (cfun);
if (init_machine_status) if (init_machine_status)
(*init_machine_status) (cfun); (*init_machine_status) (cfun);
......
...@@ -437,6 +437,9 @@ struct function ...@@ -437,6 +437,9 @@ struct function
generated. */ generated. */
unsigned int instrument_entry_exit : 1; 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. */ /* Nonzero if profiling code should be generated. */
unsigned int profile : 1; unsigned int profile : 1;
......
...@@ -24,13 +24,24 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA ...@@ -24,13 +24,24 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include <stdio.h> #include <stdio.h>
#include <sys/types.h> #include <sys/types.h>
static int __fetch_long PARAMS ((long *, char *, size_t)) ATTRIBUTE_UNUSED; static int __fetch_long PARAMS ((long *, char *, size_t))
static int __read_long PARAMS ((long *, FILE *, size_t)) ATTRIBUTE_UNUSED; ATTRIBUTE_UNUSED;
static int __write_long PARAMS ((long, FILE *, size_t)) ATTRIBUTE_UNUSED; static int __read_long PARAMS ((long *, FILE *, size_t))
static int __fetch_gcov_type PARAMS ((gcov_type *, char *, size_t)) ATTRIBUTE_UNUSED; ATTRIBUTE_UNUSED;
static int __store_gcov_type PARAMS ((gcov_type, char *, size_t)) ATTRIBUTE_UNUSED; static int __write_long PARAMS ((long, FILE *, size_t))
static int __read_gcov_type PARAMS ((gcov_type *, FILE *, size_t)) ATTRIBUTE_UNUSED; ATTRIBUTE_UNUSED;
static int __write_gcov_type PARAMS ((gcov_type, 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. */ /* These routines only work for signed values. */
...@@ -193,4 +204,94 @@ __read_long (dest, file, bytes) ...@@ -193,4 +204,94 @@ __read_long (dest, file, bytes)
return __fetch_long (dest, c, 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 */ #endif /* ! GCC_GCOV_IO_H */
...@@ -232,6 +232,7 @@ static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN; ...@@ -232,6 +232,7 @@ static void print_usage PARAMS ((int)) ATTRIBUTE_NORETURN;
static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN; static void print_version PARAMS ((void)) ATTRIBUTE_NORETURN;
static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *)); static void init_arc PARAMS ((struct adj_list *, int, int, struct bb_info *));
static struct adj_list *reverse_arcs PARAMS ((struct adj_list *)); 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 create_program_flow_graph PARAMS ((struct bb_info_list *));
static void solve_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, static void calculate_branch_probs PARAMS ((struct bb_info_list *, int,
...@@ -538,6 +539,130 @@ reverse_arcs (arcptr) ...@@ -538,6 +539,130 @@ reverse_arcs (arcptr)
return prev; 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 /* Construct the program flow graph from the .bbg file, and read in the data
in the .da file. */ in the .da file. */
...@@ -550,6 +675,29 @@ create_program_flow_graph (bptr) ...@@ -550,6 +675,29 @@ create_program_flow_graph (bptr)
int i; int i;
struct adj_list *arcptr; struct adj_list *arcptr;
struct bb_info *bb_graph; 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 the number of blocks. */
__read_long (&num_blocks, bbg_file, 4); __read_long (&num_blocks, bbg_file, 4);
...@@ -579,7 +727,10 @@ create_program_flow_graph (bptr) ...@@ -579,7 +727,10 @@ create_program_flow_graph (bptr)
init_arc (arcptr, src, dest, bb_graph); init_arc (arcptr, src, dest, bb_graph);
__read_long (&flag_bits, bbg_file, 4); __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->fake = !! (flag_bits & 0x2);
arcptr->fall_through = !! (flag_bits & 0x4); arcptr->fall_through = !! (flag_bits & 0x4);
} }
...@@ -601,6 +752,10 @@ create_program_flow_graph (bptr) ...@@ -601,6 +752,10 @@ create_program_flow_graph (bptr)
if (bb_graph[i].succ) if (bb_graph[i].succ)
bb_graph[i].succ = reverse_arcs (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 /* For each arc not on the spanning tree, set its execution count from
the .da file. */ the .da file. */
...@@ -613,15 +768,13 @@ create_program_flow_graph (bptr) ...@@ -613,15 +768,13 @@ create_program_flow_graph (bptr)
for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next) for (arcptr = bb_graph[i].succ; arcptr; arcptr = arcptr->succ_next)
if (! arcptr->on_tree) if (! arcptr->on_tree)
{ {
gcov_type tmp_count = 0; arcptr->arc_count = profile[profile_pos++];
if (da_file && __read_gcov_type (&tmp_count, da_file, 8))
abort ();
arcptr->arc_count = tmp_count;
arcptr->count_valid = 1; arcptr->count_valid = 1;
bb_graph[i].succ_count--; bb_graph[i].succ_count--;
bb_graph[arcptr->target].pred_count--; bb_graph[arcptr->target].pred_count--;
} }
free (profile);
free (function_name);
} }
static void static void
...@@ -755,12 +908,6 @@ read_files () ...@@ -755,12 +908,6 @@ read_files ()
struct stat buf; struct stat buf;
struct bb_info_list *list_end = 0; struct bb_info_list *list_end = 0;
struct bb_info_list *b_ptr; 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)) while (! feof (bbg_file))
{ {
...@@ -781,17 +928,6 @@ read_files () ...@@ -781,17 +928,6 @@ read_files ()
ungetc (getc (bbg_file), bbg_file); 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 /* Calculate all of the basic block execution counts and branch
taken probabilities. */ taken probabilities. */
......
...@@ -1238,12 +1238,11 @@ __eprintf (const char *string, const char *expression, ...@@ -1238,12 +1238,11 @@ __eprintf (const char *string, const char *expression,
#ifdef L_bb #ifdef L_bb
#if LONG_TYPE_SIZE == GCOV_TYPE_SIZE struct bb_function_info {
typedef long gcov_type; long checksum;
#else int arc_count;
typedef long long gcov_type; const char *name;
#endif };
/* Structure emitted by -a */ /* Structure emitted by -a */
struct bb struct bb
...@@ -1253,14 +1252,10 @@ struct bb ...@@ -1253,14 +1252,10 @@ struct bb
gcov_type *counts; gcov_type *counts;
long ncounts; long ncounts;
struct bb *next; struct bb *next;
const unsigned long *addresses;
/* Older GCC's did not emit these fields. */ /* Older GCC's did not emit these fields. */
long nwords; long nwords;
const char **functions; struct bb_function_info *function_infos;
const long *line_nums;
const char **filenames;
char *flags;
}; };
#ifdef BLOCK_PROFILER_CODE #ifdef BLOCK_PROFILER_CODE
...@@ -1283,39 +1278,66 @@ BLOCK_PROFILER_CODE ...@@ -1283,39 +1278,66 @@ BLOCK_PROFILER_CODE
#include <errno.h> #include <errno.h>
#endif #endif
#include <gthr.h>
static struct bb *bb_head; static struct bb *bb_head;
int __global_counters = 0, __gthreads_active = 0;
void void
__bb_exit_func (void) __bb_exit_func (void)
{ {
FILE *da_file; FILE *da_file;
int i;
struct bb *ptr; struct bb *ptr;
long n_counters_p = 0;
gcov_type max_counter_p = 0;
gcov_type sum_counters_p = 0;
if (bb_head == 0) if (bb_head == 0)
return; 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) 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 - for (i = 0; i < ptr->ncounts; i++)
but don't clobber exiting data. */ {
if ((da_file = fopen (ptr->filename, "a")) != 0) sum_counters_o += ptr->counts[i];
fclose (da_file);
/* Need to re-open in order to be able to write from the start. */ if (ptr->counts[i] > max_counter_o)
da_file = fopen (ptr->filename, "r+b"); 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. /* Some old systems might not allow the 'b' mode modifier.
Therefore, try to open without it. This can lead to a race Therefore, try to open without it. This can lead to a race
condition so that when you delete and re-create the file, the condition so that when you delete and re-create the file, the
file might be opened in text mode, but then, you shouldn't file might be opened in text mode, but then, you shouldn't
delete the file in the first place. */ delete the file in the first place. */
if (da_file == 0) if (da_file == 0)
da_file = fopen (ptr->filename, "r+"); da_file = fopen (ptr->filename, "a");
if (da_file == 0) if (da_file == 0)
{ {
fprintf (stderr, "arc profiling: Can't open output file %s.\n", fprintf (stderr, "arc profiling: Can't open output file %s.\n",
...@@ -1341,92 +1363,96 @@ __bb_exit_func (void) ...@@ -1341,92 +1363,96 @@ __bb_exit_func (void)
} }
#endif #endif
/* If the file is not empty, and the number of counts in it is the if (__write_long (-123, da_file, 4) != 0) /* magic */
same, then merge them in. */
firstchar = fgetc (da_file);
if (firstchar == EOF)
{ {
if (ferror (da_file)) fprintf (stderr, "arc profiling: Error writing output file %s.\n",
{ ptr->filename);
fprintf (stderr, "arc profiling: Can't read output file ");
perror (ptr->filename);
}
} }
else 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; /* new function. */
if (__write_gcov_string
for (i = 0; i < n_counts; i++) (fn_info->name, strlen (fn_info->name), da_file, -1) != 0)
{ {
gcov_type v = 0; fprintf (stderr,
"arc profiling: Error writing output file %s.\n",
if (__read_gcov_type (&v, da_file, 8) != 0) ptr->filename);
{ break;
fprintf (stderr,
"arc profiling: Can't read output file %s.\n",
ptr->filename);
break;
}
ptr->counts[i] += v;
} }
}
} if (__write_long (fn_info->checksum, da_file, 4) != 0)
{
rewind (da_file); fprintf (stderr,
"arc profiling: Error writing output file %s.\n",
/* ??? Should first write a header to the file. Preferably, a 4 byte ptr->filename);
magic number, 4 bytes containing the time the program was break;
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/ if (__write_long (fn_info->arc_count, da_file, 4) != 0)
data file combination is being used from gcov. */ {
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", if (i) /* there was an error */
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)
{ {
ret = 1; fprintf (stderr,
"arc profiling: Error writing output file %s.\n",
ptr->filename);
break; 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", fprintf (stderr, "arc profiling: Error closing output file %s.\n",
ptr->filename); ptr->filename);
} }
return;
} }
void void
...@@ -1437,8 +1463,8 @@ __bb_init_func (struct bb *blocks) ...@@ -1437,8 +1463,8 @@ __bb_init_func (struct bb *blocks)
if (blocks->zero_word) if (blocks->zero_word)
return; return;
/* Initialize destructor. */ /* Initialize destructor and per-thread data. */
if (!bb_head) if (!bb_head)
atexit (__bb_exit_func); atexit (__bb_exit_func);
...@@ -1451,7 +1477,7 @@ __bb_init_func (struct bb *blocks) ...@@ -1451,7 +1477,7 @@ __bb_init_func (struct bb *blocks)
/* Called before fork or exec - write out profile information gathered so /* Called before fork or exec - write out profile information gathered so
far and reset it to zero. This avoids duplication or loss of the far and reset it to zero. This avoids duplication or loss of the
profile information gathered so far. */ profile information gathered so far. */
void void
__bb_fork_func (void) __bb_fork_func (void)
{ {
struct bb *ptr; struct bb *ptr;
......
...@@ -31,9 +31,14 @@ struct bb; ...@@ -31,9 +31,14 @@ struct bb;
extern void __bb_exit_func (void); extern void __bb_exit_func (void);
extern void __bb_init_func (struct bb *); extern void __bb_init_func (struct bb *);
extern void __bb_fork_func (void); extern void __bb_fork_func (void);
extern void __bb_trace_func (void);
extern void __bb_trace_ret (void); #if LONG_TYPE_SIZE == GCOV_TYPE_SIZE
extern void __bb_init_trace_func (struct bb *, unsigned long); typedef long gcov_type;
#else
typedef long long gcov_type;
#endif
extern gcov_type *__bb_find_arc_counters (void);
struct exception_descriptor; struct exception_descriptor;
extern short int __get_eh_table_language (struct exception_descriptor *); extern short int __get_eh_table_language (struct exception_descriptor *);
......
...@@ -364,6 +364,11 @@ int profile_flag = 0; ...@@ -364,6 +364,11 @@ int profile_flag = 0;
int profile_arc_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. */ /* Nonzero if generating info for gcov to calculate line test coverage. */
int flag_test_coverage = 0; int flag_test_coverage = 0;
...@@ -1061,6 +1066,8 @@ static const lang_independent_options f_options[] = ...@@ -1061,6 +1066,8 @@ static const lang_independent_options f_options[] =
N_("Support synchronous non-call exceptions") }, N_("Support synchronous non-call exceptions") },
{"profile-arcs", &profile_arc_flag, 1, {"profile-arcs", &profile_arc_flag, 1,
N_("Insert arc based program profiling code") }, 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, {"test-coverage", &flag_test_coverage, 1,
N_("Create data files needed by gcov") }, N_("Create data files needed by gcov") },
{"branch-probabilities", &flag_branch_probabilities, 1, {"branch-probabilities", &flag_branch_probabilities, 1,
...@@ -2891,14 +2898,13 @@ rest_of_compilation (decl) ...@@ -2891,14 +2898,13 @@ rest_of_compilation (decl)
close_dump_file (DFI_cfg, print_rtl_with_bb, insns); close_dump_file (DFI_cfg, print_rtl_with_bb, insns);
/* Do branch profiling and static profile estimation passes. */ /* Do branch profiling and static profile estimation passes. */
if (optimize > 0 || profile_arc_flag || flag_test_coverage if (optimize > 0 || cfun->arc_profile || flag_branch_probabilities)
|| flag_branch_probabilities)
{ {
struct loops loops; struct loops loops;
timevar_push (TV_BRANCH_PROB); timevar_push (TV_BRANCH_PROB);
open_dump_file (DFI_bp, decl); 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 (); branch_prob ();
/* Discover and record the loop depth at the head of each basic /* Discover and record the loop depth at the head of each basic
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment