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