aboutsummaryrefslogtreecommitdiff
path: root/gcc/libgcov.c
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2003-04-23 14:05:11 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2003-04-23 14:05:11 +0000
commitcdb2376773696240929622b1504fa8e2d4c29843 (patch)
tree120a1c15af28d004dc01bf0ac13ef734a28142cb /gcc/libgcov.c
parent2be3b5ce222dcf49dcca9e9bf3f1f7eb77b64566 (diff)
downloadgcc-cdb2376773696240929622b1504fa8e2d4c29843.zip
gcc-cdb2376773696240929622b1504fa8e2d4c29843.tar.gz
gcc-cdb2376773696240929622b1504fa8e2d4c29843.tar.bz2
Makefile.in (LIBGCC_DEPS): Add gcov headers.
* Makefile.in (LIBGCC_DEPS): Add gcov headers. (libgcov.a): Depends on LIBGCC_DEPS. * basic-block.h (profile_info): Moved here from coverage.h. Made a pointer. * coverage.c (struct function_list): Fixed array of counter types. (struct counts_entry): Keyed by counter type, contains summary. (profile_info): Moved to profile.c. (prg_ctr_mask, prg_n_ctrs, fn_ctr_mask, fn_n_ctrs): New global vars. (profiler_label): Remove. (ctr_labels): New. (set_purpose, label_for_tag, build_counter_section_fields, build_counter_section_value, build_counter_section_data_fields, build_counter_section_data_values, build_function_info_fields, build_function_info_value, gcov_info_fields, gcov_info_value): Remove. (build_fn_info_type, build_fn_info_value, build_ctr_info_type, build_ctr_info_value, build_gcov_info): New. (htab_counts_entry_hash, htab_counts_entry_eq): Adjust. (reads_counts_file): Adjust. (get_coverage_counts): Takes counter number. Add summary parameter. Adjust. (coverage_counter_ref): Tkaes counter number. Adjust. Lazily create counter array labels. (coverage_end_function): Adjust. (create_coverage): Adjust. (find_counters_section): Remove. * coverage.h (MAX_COUNTER_SECTIONS): Remove. (struct section_info, struct profile_info): Remove. (profile_info): Moved to basic-block.h. (coverage_counter_ref): Takes a counter number. (get_coverage_counts): Takes a counter number. Added summary parameter. (find_counters_section): Remove. * gcov-dump.c (tag_arc_counts): Rename to ... (tag_counters): ... here. Adjust. (tag_table): Move tag_counters to 3rd entry. Remove PROGRAM_PLACEHOLDER and PROGRAM_INCORRECT entries. (dump_file): Check for counter tag values here. (tag_summary): Adjust. * gcov-io.c (gcov_write_summary, gcov_read_summary): Adjust. * gcov-io.h (GCOV_LOCKED): New. (GCOV_TAG_ARC_COUNTS): Rename to ... (GCOV_TAG_COUNTS_BASE): ... here. (GCOV_TAG_PLACEHOLDER_SUMMARY, GCOV_TAG_INCORRECT_SUMMARY): Remove. (GCOV_COUNTER_ARCS, GCOV_COUNTERS, GCOV_NAMES): New. (GCOV_TAG_FOR_COUNTER, GCOV_COUNTER_FOR_TAG, GCOV_TAG_IS_COUNTER): New. (struct gcov_ctr_summary): New. (struct gcov_summary): Adjust. (struct gcov_counter_section): Remove. struct gcov_counter_section_data): Remove. (struct gcov_function_info): Rename to ... (struct gcov_fn_info): ... here. Adjust. (struct gcov_ctr_info): New. (struct gcov_info): Adjust. * gcov.c (read_count_file): Adjust. (output_lines): Adjust. * libgcov.c (gcov_exit): Adjust. (__gcov_flush): Adjust. * mklibgcc.in (libgcc2_c_dep): Add gcov headers. * predict.c (maybe_hot_bb_p, probably_cold_bb_p, probably_never_executed_bb_p, compute_frequency_function): Adjust profile_info use. * profile.c (struct counts_entry): Remove. (profile_info): Define here. (get_exec_counts): Adjust get_coverage_counts call. (compute_branch_probablilities): Remove find_counters_section call. (gen_edge_profiler): Adjust coverage_counter_ref call. * tracer.c (tail_duplicate): Adjust profile_info use. From-SVN: r65990
Diffstat (limited to 'gcc/libgcov.c')
-rw-r--r--gcc/libgcov.c420
1 files changed, 200 insertions, 220 deletions
diff --git a/gcc/libgcov.c b/gcc/libgcov.c
index 237da2d..a2c831e 100644
--- a/gcc/libgcov.c
+++ b/gcc/libgcov.c
@@ -96,93 +96,91 @@ gcov_version_mismatch (struct gcov_info *ptr, unsigned version)
static void
gcov_exit (void)
{
- struct gcov_info *ptr;
- unsigned ix, jx;
- gcov_type program_max_one = 0;
- gcov_type program_sum = 0;
- unsigned program_arcs = 0;
- struct gcov_summary last_prg;
-
- last_prg.runs = 0;
-
- for (ptr = gcov_list; ptr; ptr = ptr->next)
+ struct gcov_info *gi_ptr;
+ struct gcov_summary this_program;
+ struct gcov_summary all;
+
+ memset (&all, 0, sizeof (all));
+ /* Find the totals for this execution. */
+ memset (&this_program, 0, sizeof (this_program));
+ for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
- unsigned arc_data_index;
- gcov_type *count_ptr;
-
- if (!ptr->filename)
- continue;
-
- for (arc_data_index = 0;
- arc_data_index < ptr->n_counter_sections
- && ptr->counter_sections[arc_data_index].tag != GCOV_TAG_ARC_COUNTS;
- arc_data_index++)
- continue;
-
- for (ix = ptr->counter_sections[arc_data_index].n_counters,
- count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;)
- {
- gcov_type count = *count_ptr++;
-
- if (count > program_max_one)
- program_max_one = count;
- program_sum += count;
- }
- program_arcs += ptr->counter_sections[arc_data_index].n_counters;
+ const struct gcov_ctr_info *ci_ptr;
+ struct gcov_ctr_summary *cs_ptr;
+ unsigned t_ix;
+
+ for (t_ix = 0, ci_ptr = gi_ptr->counts, cs_ptr = this_program.ctrs;
+ t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
+ if ((1 << t_ix) & gi_ptr->ctr_mask)
+ {
+ const gcov_type *c_ptr;
+ unsigned c_num;
+
+ cs_ptr->num += ci_ptr->num;
+ for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
+ {
+ cs_ptr->sum_all += *c_ptr;
+ if (cs_ptr->run_max < *c_ptr)
+ cs_ptr->run_max = *c_ptr;
+ }
+ ci_ptr++;
+ }
}
- for (ptr = gcov_list; ptr; ptr = ptr->next)
+
+ /* Now write the data */
+ for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
- struct gcov_summary object;
- struct gcov_summary local_prg;
+ struct gcov_summary this_object;
+ struct gcov_summary object, program;
+ gcov_type *values[GCOV_COUNTERS];
+ const struct gcov_fn_info *fi_ptr;
+ unsigned fi_stride;
+ unsigned c_ix, t_ix, f_ix;
+ const struct gcov_ctr_info *ci_ptr;
+ struct gcov_ctr_summary *cs_ptr;
+ struct gcov_ctr_summary *cs_obj, *cs_tobj, *cs_prg, *cs_tprg, *cs_all;
int error;
int merging;
unsigned long base;
- const struct gcov_function_info *fn_info;
- gcov_type **counters;
- gcov_type *count_ptr;
- gcov_type object_max_one = 0;
unsigned tag, length;
- unsigned arc_data_index, f_sect_index, sect_index;
- long summary_pos = 0;
-
- if (!ptr->filename)
- continue;
-
- counters = malloc (sizeof (gcov_type *) * ptr->n_counter_sections);
- for (ix = 0; ix < ptr->n_counter_sections; ix++)
- counters[ix] = ptr->counter_sections[ix].counters;
-
- for (arc_data_index = 0;
- arc_data_index < ptr->n_counter_sections
- && ptr->counter_sections[arc_data_index].tag != GCOV_TAG_ARC_COUNTS;
- arc_data_index++)
- continue;
-
- if (arc_data_index == ptr->n_counter_sections)
+ unsigned long summary_pos = 0;
+
+ /* Totals for this object file. */
+ memset (&this_object, 0, sizeof (this_object));
+ for (t_ix = c_ix = 0,
+ ci_ptr = gi_ptr->counts, cs_ptr = this_object.ctrs;
+ t_ix != GCOV_COUNTERS; t_ix++, cs_ptr++)
+ if ((1 << t_ix) & gi_ptr->ctr_mask)
+ {
+ const gcov_type *c_ptr;
+ unsigned c_num;
+
+ cs_ptr->num += ci_ptr->num;
+ values[c_ix] = ci_ptr->values;
+ for (c_num = ci_ptr->num, c_ptr = ci_ptr->values; c_num--; c_ptr++)
+ {
+ cs_ptr->sum_all += *c_ptr;
+ if (cs_ptr->run_max < *c_ptr)
+ cs_ptr->run_max = *c_ptr;
+ }
+ c_ix++;
+ ci_ptr++;
+ }
+
+ /* Calculate the function_info stride. This depends on the
+ number of counter types being measured. */
+ fi_stride = sizeof (struct gcov_fn_info) + c_ix * sizeof (unsigned);
+ if (__alignof__ (struct gcov_fn_info) > sizeof (unsigned))
{
- /* For now; later we may want to just measure other profiles,
- but now I am lazy to check for all consequences. */
- abort ();
+ fi_stride += __alignof__ (struct gcov_fn_info) - 1;
+ fi_stride &= ~(__alignof__ (struct gcov_fn_info) - 1);
}
- for (ix = ptr->counter_sections[arc_data_index].n_counters,
- count_ptr = ptr->counter_sections[arc_data_index].counters; ix--;)
- {
- gcov_type count = *count_ptr++;
-
- if (count > object_max_one)
- object_max_one = count;
- }
-
- memset (&local_prg, 0, sizeof (local_prg));
- memset (&object, 0, sizeof (object));
-
- /* Open for modification */
- merging = gcov_open (ptr->filename, 0);
+ /* Open for modification, if possible */
+ merging = gcov_open (gi_ptr->filename, 0);
if (!merging)
{
- fprintf (stderr, "profiling:%s:Cannot open\n", ptr->filename);
- ptr->filename = 0;
+ fprintf (stderr, "profiling:%s:Cannot open\n", gi_ptr->filename);
continue;
}
@@ -192,22 +190,22 @@ gcov_exit (void)
if (gcov_read_unsigned () != GCOV_DATA_MAGIC)
{
fprintf (stderr, "profiling:%s:Not a gcov data file\n",
- ptr->filename);
+ gi_ptr->filename);
read_fatal:;
gcov_close ();
- ptr->filename = 0;
continue;
}
length = gcov_read_unsigned ();
if (length != GCOV_VERSION)
{
- gcov_version_mismatch (ptr, length);
+ gcov_version_mismatch (gi_ptr, length);
goto read_fatal;
}
/* Merge execution counts for each function. */
- for (ix = ptr->n_functions, fn_info = ptr->functions;
- ix--; fn_info++)
+ for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
+ fi_ptr = (const struct gcov_fn_info *)
+ ((const char *) fi_ptr + fi_stride))
{
tag = gcov_read_unsigned ();
length = gcov_read_unsigned ();
@@ -216,42 +214,34 @@ gcov_exit (void)
if (tag != GCOV_TAG_FUNCTION)
{
read_mismatch:;
- fprintf (stderr, "profiling:%s:Merge mismatch at %s\n",
- ptr->filename, fn_info->name);
+ fprintf (stderr, "profiling:%s:Merge mismatch for %s\n",
+ gi_ptr->filename,
+ fi_ptr ? fi_ptr->name : "summaries");
goto read_fatal;
}
- if (strcmp (gcov_read_string (), fn_info->name)
- || gcov_read_unsigned () != fn_info->checksum)
+ if (strcmp (gcov_read_string (), fi_ptr->name)
+ || gcov_read_unsigned () != fi_ptr->checksum)
goto read_mismatch;
- /* Counters. */
- for (f_sect_index = 0;
- f_sect_index < fn_info->n_counter_sections;
- f_sect_index++)
- {
- unsigned n_counters;
-
- tag = gcov_read_unsigned ();
- length = gcov_read_unsigned ();
-
- for (sect_index = 0;
- sect_index < ptr->n_counter_sections;
- sect_index++)
- if (ptr->counter_sections[sect_index].tag == tag)
- break;
- if (sect_index == ptr->n_counter_sections
- || fn_info->counter_sections[f_sect_index].tag != tag)
- goto read_mismatch;
-
- n_counters = fn_info->counter_sections[f_sect_index].n_counters;
- if (n_counters != length / 8)
- goto read_mismatch;
-
- for (jx = 0; jx < n_counters; jx++)
- counters[sect_index][jx] += gcov_read_counter ();
-
- counters[sect_index] += n_counters;
+ for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
+ if ((1 << t_ix) & gi_ptr->ctr_mask)
+ {
+ unsigned n_counts;
+ gcov_type *c_ptr;
+
+ tag = gcov_read_unsigned ();
+ length = gcov_read_unsigned ();
+
+ if (tag != GCOV_TAG_FOR_COUNTER (t_ix)
+ || fi_ptr->n_ctrs[c_ix] * 8 != length)
+ goto read_mismatch;
+ c_ptr = values[c_ix];
+ for (n_counts = fi_ptr->n_ctrs[c_ix];
+ n_counts--; c_ptr++)
+ *c_ptr += gcov_read_counter ();
+ values[c_ix] = c_ptr;
+ c_ix++;
}
if ((error = gcov_is_error ()))
goto read_error;
@@ -266,148 +256,134 @@ gcov_exit (void)
/* Check program summary */
while (!gcov_is_eof ())
{
- unsigned long base = gcov_position ();
-
+ base = gcov_position ();
tag = gcov_read_unsigned ();
gcov_read_unsigned ();
if (tag != GCOV_TAG_PROGRAM_SUMMARY)
goto read_mismatch;
- gcov_read_summary (&local_prg);
+ gcov_read_summary (&program);
if ((error = gcov_is_error ()))
{
read_error:;
fprintf (stderr, error < 0 ?
"profiling:%s:Overflow merging\n" :
"profiling:%s:Error merging\n",
- ptr->filename);
+ gi_ptr->filename);
goto read_fatal;
}
- if (local_prg.checksum != gcov_crc32)
- {
- memset (&local_prg, 0, sizeof (local_prg));
- continue;
- }
- merging = 0;
- if (tag != GCOV_TAG_PROGRAM_SUMMARY)
- break;
-
- /* If everything done correctly, the summaries should be
- computed equal for each module. */
- if (last_prg.runs
-#ifdef TARGET_HAS_F_SETLKW
- && last_prg.runs == local_prg.runs
-#endif
- && memcmp (&last_prg, &local_prg, sizeof (last_prg)))
- {
-#ifdef TARGET_HAS_F_SETLKW
- fprintf (stderr, "profiling:%s:Invocation mismatch\n\
-Probably some files were removed\n",
- ptr->filename);
-#else
- fprintf (stderr, "profiling:%s:Invocation mismatch\n\
-Probably some files were removed or parallel race happent because libgcc\n\
-is compiled without file locking support.\n",
- ptr->filename);
-#endif
- local_prg.runs = 0;
- }
- else
- memcpy (&last_prg, &local_prg, sizeof (last_prg));
+ if (program.checksum != gcov_crc32)
+ continue;
summary_pos = base;
break;
}
gcov_seek (0, 0);
}
+ else
+ memset (&object, 0, sizeof (object));
+ if (!summary_pos)
+ memset (&program, 0, sizeof (program));
- object.runs++;
- object.arcs = ptr->counter_sections[arc_data_index].n_counters;
- object.arc_sum = 0;
- if (object.arc_max_one < object_max_one)
- object.arc_max_one = object_max_one;
- object.arc_sum_max += object_max_one;
+ fi_ptr = 0;
+
+ /* Merge the summaries. */
+ for (t_ix = c_ix = 0,
+ cs_obj = object.ctrs, cs_tobj = this_object.ctrs,
+ cs_prg = program.ctrs, cs_tprg = this_program.ctrs,
+ cs_all = all.ctrs;
+ t_ix != GCOV_COUNTERS;
+ t_ix++, cs_obj++, cs_tobj++, cs_prg++, cs_tprg++, cs_all++)
+ {
+ if ((1 << t_ix) & gi_ptr->ctr_mask)
+ {
+ if (!cs_obj->runs++)
+ cs_obj->num = cs_tobj->num;
+ else if (cs_obj->num != cs_tobj->num)
+ goto read_mismatch;
+ cs_obj->sum_all += cs_tobj->sum_all;
+ if (cs_obj->run_max < cs_tobj->run_max)
+ cs_obj->run_max = cs_tobj->run_max;
+ cs_obj->sum_max += cs_tobj->run_max;
+
+ if (!cs_prg->runs++)
+ cs_prg->num = cs_tprg->num;
+ else if (cs_prg->num != cs_tprg->num)
+ goto read_mismatch;
+ cs_prg->sum_all += cs_tprg->sum_all;
+ if (cs_prg->run_max < cs_tprg->run_max)
+ cs_prg->run_max = cs_tprg->run_max;
+ cs_prg->sum_max += cs_tprg->run_max;
+
+ values[c_ix] = gi_ptr->counts[c_ix].values;
+ c_ix++;
+ }
+ else if (cs_obj->num || cs_prg->num)
+ goto read_mismatch;
+
+ if (!cs_all->runs && cs_prg->runs)
+ memcpy (cs_all, cs_prg, sizeof (*cs_all));
+ else if (!all.checksum
+ && (!GCOV_LOCKED || cs_all->runs == cs_prg->runs)
+ && memcmp (cs_all, cs_prg, sizeof (*cs_all)))
+ {
+ fprintf (stderr, "profiling:%s:Invocation mismatch - some data files may have been removed%s",
+ gi_ptr->filename, GCOV_LOCKED
+ ? "" : " or concurrent update without locking support");
+ all.checksum = ~0u;
+ }
+ }
+
+ program.checksum = gcov_crc32;
/* Write out the data. */
gcov_write_unsigned (GCOV_DATA_MAGIC);
gcov_write_unsigned (GCOV_VERSION);
/* Write execution counts for each function. */
- for (ix = 0; ix < ptr->n_counter_sections; ix++)
- counters[ix] = ptr->counter_sections[ix].counters;
- for (ix = ptr->n_functions, fn_info = ptr->functions; ix--; fn_info++)
+ for (f_ix = gi_ptr->n_functions, fi_ptr = gi_ptr->functions; f_ix--;
+ fi_ptr = (const struct gcov_fn_info *)
+ ((const char *) fi_ptr + fi_stride))
{
/* Announce function. */
base = gcov_write_tag (GCOV_TAG_FUNCTION);
- gcov_write_string (fn_info->name);
- gcov_write_unsigned (fn_info->checksum);
+ gcov_write_string (fi_ptr->name);
+ gcov_write_unsigned (fi_ptr->checksum);
gcov_write_length (base);
- /* counters. */
- for (f_sect_index = 0;
- f_sect_index < fn_info->n_counter_sections;
- f_sect_index++)
- {
- tag = fn_info->counter_sections[f_sect_index].tag;
- for (sect_index = 0;
- sect_index < ptr->n_counter_sections;
- sect_index++)
- if (ptr->counter_sections[sect_index].tag == tag)
- break;
- if (sect_index == ptr->n_counter_sections)
- abort ();
-
- base = gcov_write_tag (tag);
- for (jx = fn_info->counter_sections[f_sect_index].n_counters; jx--;)
- {
- gcov_type count = *counters[sect_index]++;
-
- if (tag == GCOV_TAG_ARC_COUNTS)
- {
- object.arc_sum += count;
- }
- gcov_write_counter (count);
- }
- gcov_write_length (base);
- }
+ for (c_ix = t_ix = 0; t_ix != GCOV_COUNTERS; t_ix++)
+ if ((1 << t_ix) & gi_ptr->ctr_mask)
+ {
+ unsigned n_counts;
+ gcov_type *c_ptr;
+
+ base = gcov_write_tag (GCOV_TAG_FOR_COUNTER (t_ix));
+ c_ptr = values[c_ix];
+ for (n_counts = fi_ptr->n_ctrs[c_ix]; n_counts--; c_ptr++)
+ gcov_write_counter (*c_ptr);
+ values[c_ix] = c_ptr;
+ gcov_write_length (base);
+ c_ix++;
+ }
}
/* Object file summary. */
gcov_write_summary (GCOV_TAG_OBJECT_SUMMARY, &object);
/* Generate whole program statistics. */
- local_prg.runs++;
- local_prg.checksum = gcov_crc32;
- local_prg.arcs = program_arcs;
- local_prg.arc_sum += program_sum;
- if (local_prg.arc_max_one < program_max_one)
- local_prg.arc_max_one = program_max_one;
- local_prg.arc_sum_max += program_max_one;
-
- if (merging)
- {
- gcov_seek_end ();
- gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &local_prg);
- }
- else if (summary_pos)
- {
- /* Zap trailing program summary */
- gcov_seek (summary_pos, 0);
- if (!local_prg.runs)
- ptr->wkspc = 0;
- gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &local_prg);
- }
- if (gcov_close ())
+ if (summary_pos)
+ gcov_seek (summary_pos, 0);
+ else
+ gcov_seek_end ();
+ gcov_write_summary (GCOV_TAG_PROGRAM_SUMMARY, &program);
+ if ((error = gcov_close ()))
{
- fprintf (stderr, "profiling:%s:Error writing\n", ptr->filename);
- ptr->filename = 0;
+ fprintf (stderr, error < 0 ?
+ "profiling:%s:Overflow writing\n" :
+ "profiling:%s:Error writing\n",
+ gi_ptr->filename);
+ gi_ptr->filename = 0;
}
}
- /* All statistic we gather can be done in one pass trought the file.
- Originally we did two - one for counts and other for the statistics. This
- brings problem with the file locking interface, but it is possible to
- implement so if need appears in the future - first pass updates local
- statistics and number of runs. Second pass then overwrite global
- statistics only when number of runs match. */
}
/* Add a new object file onto the bb chain. Invoked automatically
@@ -459,16 +435,20 @@ __gcov_init (struct gcov_info *info)
void
__gcov_flush (void)
{
- struct gcov_info *ptr;
+ const struct gcov_info *gi_ptr;
gcov_exit ();
- for (ptr = gcov_list; ptr; ptr = ptr->next)
+ for (gi_ptr = gcov_list; gi_ptr; gi_ptr = gi_ptr->next)
{
- unsigned i, j;
+ unsigned t_ix;
+ const struct gcov_ctr_info *ci_ptr;
- for (j = 0; j < ptr->n_counter_sections; j++)
- for (i = ptr->counter_sections[j].n_counters; i--;)
- ptr->counter_sections[j].counters[i] = 0;
+ for (t_ix = 0, ci_ptr = gi_ptr->counts; t_ix != GCOV_COUNTERS; t_ix++)
+ if ((1 << t_ix) & gi_ptr->ctr_mask)
+ {
+ memset (ci_ptr->values, 0, sizeof (gcov_type) * ci_ptr->num);
+ ci_ptr++;
+ }
}
}