mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-27 05:44:15 +08:00
Add overlap functionality to gcov-tool.
2014-10-08 Rong Xu <xur@google.com> * gcc/gcov-tool.c (profile_overlap): New driver function to compute profile overlap. (print_overlap_usage_message): New. (overlap_usage): New. (do_overlap): New. (print_usage): Add calls to overlap function. (main): Ditto. * libgcc/libgcov-util.c (read_gcda_file): Fix format. (find_match_gcov_info): Ditto. (calculate_2_entries): New. (compute_one_gcov): Ditto. (gcov_info_count_all_cold): Ditto. (gcov_info_count_all_zero): Ditto. (extract_file_basename): Ditto. (get_file_basename): Ditto. (set_flag): Ditto. (matched_gcov_info): Ditto. (calculate_overlap): Ditto. (gcov_profile_overlap): Ditto. * libgcc/libgcov-driver.c (compute_summary): Make it avavilable for external calls. * gcc/doc/gcov-tool.texi: Add documentation. From-SVN: r216015
This commit is contained in:
parent
a41bb2c947
commit
9b84e7a836
@ -1,3 +1,14 @@
|
||||
2014-10-08 Rong Xu <xur@google.com>
|
||||
|
||||
* gcov-tool.c (profile_overlap): New driver function
|
||||
to compute profile overlap.
|
||||
(print_overlap_usage_message): New.
|
||||
(overlap_usage): New.
|
||||
(do_overlap): New.
|
||||
(print_usage): Add calls to overlap function.
|
||||
(main): Ditto.
|
||||
* doc/gcov-tool.texi: Add documentation.
|
||||
|
||||
2014-10-08 Steve Ellcey <sellcey@mips.com>
|
||||
|
||||
* config/mips/mti-linux.h (DRIVER_SELF_SPECS): Change
|
||||
|
@ -103,8 +103,7 @@ in these kind of counters.
|
||||
@section Invoking @command{gcov-tool}
|
||||
|
||||
@smallexample
|
||||
gcov-tool @r{[}@var{global-options}@r{]} SUB_COMMAND
|
||||
@r{[}@var{sub_command-options}@r{]} @var{profile_dir}
|
||||
gcov-tool @r{[}@var{global-options}@r{]} SUB_COMMAND @r{[}@var{sub_command-options}@r{]} @var{profile_dir}
|
||||
@end smallexample
|
||||
|
||||
@command{gcov-tool} accepts the following options:
|
||||
@ -123,6 +122,15 @@ gcov-tool rewrite [rewrite-options] @var{directory}
|
||||
[@option{-o}|@option{--output} @var{directory}]
|
||||
[@option{-s}|@option{--scale} @var{float_or_simple-frac_value}]
|
||||
[@option{-n}|@option{--normalize} @var{long_long_value}]
|
||||
|
||||
gcov-tool overlap [overlap-options] @var{directory1} @var{directory2}
|
||||
[@option{-v}|@option{--verbose}]
|
||||
[@option{-h}|@option{--hotonly}]
|
||||
[@option{-f}|@option{--function}]
|
||||
[@option{-F}|@option{--fullname}]
|
||||
[@option{-o}|@option{--object}]
|
||||
[@option{-t}|@option{--hot_threshold}] @var{float}
|
||||
|
||||
@c man end
|
||||
@c man begin SEEALSO
|
||||
gpl(7), gfdl(7), fsf-funding(7), gcc(1), gcov(1) and the Info entry for
|
||||
@ -182,8 +190,42 @@ or simple fraction value form, such 1, 2, 2/3, and 5/3.
|
||||
@itemx --normalize <long_long_value>
|
||||
Normalize the profile. The specified value is the max counter value
|
||||
in the new profile.
|
||||
|
||||
@end table
|
||||
|
||||
@item overlap
|
||||
Computer the overlap score between the two specified profile directories.
|
||||
The overlap score is computed based on the arc profiles. It is defined as
|
||||
the sum of min (p1_counter[i] / p1_sum_all, p2_counter[i] / p2_sum_all),
|
||||
for all arc counter i, where p1_counter[i] and p2_counter[i] are two
|
||||
matched counters and p1_sum_all and p2_sum_all are the sum of counter
|
||||
values in profile 1 and profile 2, respectively.
|
||||
|
||||
@table @gcctabopt
|
||||
@item -v
|
||||
@itemx --verbose
|
||||
Set the verbose mode.
|
||||
|
||||
@item -h
|
||||
@itemx --hotonly
|
||||
Only print info for hot objects/functions.
|
||||
|
||||
@item -f
|
||||
@itemx --function
|
||||
Print function level overlap score.
|
||||
|
||||
@item -F
|
||||
@itemx --fullname
|
||||
Print full gcda filename.
|
||||
|
||||
@item -o
|
||||
@itemx --object
|
||||
Print object level overlap score.
|
||||
|
||||
@item -t @var{float}
|
||||
@itemx --hot_threshold <float>
|
||||
Set the threshold for hot counter value.
|
||||
@end table
|
||||
|
||||
@end table
|
||||
|
||||
@c man end
|
||||
|
119
gcc/gcov-tool.c
119
gcc/gcov-tool.c
@ -39,6 +39,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
||||
#include <getopt.h>
|
||||
|
||||
extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int);
|
||||
extern int gcov_profile_overlap (struct gcov_info*, struct gcov_info*);
|
||||
extern int gcov_profile_normalize (struct gcov_info*, gcov_type);
|
||||
extern int gcov_profile_scale (struct gcov_info*, float, int, int);
|
||||
extern struct gcov_info* gcov_read_profile_dir (const char*, int);
|
||||
@ -368,6 +369,121 @@ do_rewrite (int argc, char **argv)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Driver function to computer the overlap score b/w profile D1 and D2.
|
||||
Return 1 on error and 0 if OK. */
|
||||
|
||||
static int
|
||||
profile_overlap (const char *d1, const char *d2)
|
||||
{
|
||||
struct gcov_info *d1_profile;
|
||||
struct gcov_info *d2_profile;
|
||||
|
||||
d1_profile = gcov_read_profile_dir (d1, 0);
|
||||
if (!d1_profile)
|
||||
return 1;
|
||||
|
||||
if (d2)
|
||||
{
|
||||
d2_profile = gcov_read_profile_dir (d2, 0);
|
||||
if (!d2_profile)
|
||||
return 1;
|
||||
|
||||
return gcov_profile_overlap (d1_profile, d2_profile);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Usage message for profile overlap. */
|
||||
|
||||
static void
|
||||
print_overlap_usage_message (int error_p)
|
||||
{
|
||||
FILE *file = error_p ? stderr : stdout;
|
||||
|
||||
fnotice (file, " overlap [options] <dir1> <dir2> Compute the overlap of two profiles\n");
|
||||
fnotice (file, " -v, --verbose Verbose mode\n");
|
||||
fnotice (file, " -h, --hotonly Only print info for hot objects/functions\n");
|
||||
fnotice (file, " -f, --function Print function level info\n");
|
||||
fnotice (file, " -F, --fullname Print full filename\n");
|
||||
fnotice (file, " -o, --object Print object level info\n");
|
||||
fnotice (file, " -t <float>, --hot_threshold <float> Set the threshold for hotness\n");
|
||||
|
||||
}
|
||||
|
||||
static const struct option overlap_options[] =
|
||||
{
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "function", no_argument, NULL, 'f' },
|
||||
{ "fullname", no_argument, NULL, 'F' },
|
||||
{ "object", no_argument, NULL, 'o' },
|
||||
{ "hotonly", no_argument, NULL, 'h' },
|
||||
{ "hot_threshold", required_argument, NULL, 't' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/* Print overlap usage and exit. */
|
||||
|
||||
static void
|
||||
overlap_usage (void)
|
||||
{
|
||||
fnotice (stderr, "Overlap subcomand usage:");
|
||||
print_overlap_usage_message (true);
|
||||
exit (FATAL_EXIT_CODE);
|
||||
}
|
||||
|
||||
int overlap_func_level;
|
||||
int overlap_obj_level;
|
||||
int overlap_hot_only;
|
||||
int overlap_use_fullname;
|
||||
double overlap_hot_threshold = 0.005;
|
||||
|
||||
/* Driver for profile overlap sub-command. */
|
||||
|
||||
static int
|
||||
do_overlap (int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
int ret;
|
||||
|
||||
optind = 0;
|
||||
while ((opt = getopt_long (argc, argv, "vfFoht:", overlap_options, NULL)) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'v':
|
||||
verbose = true;
|
||||
gcov_set_verbose ();
|
||||
break;
|
||||
case 'f':
|
||||
overlap_func_level = 1;
|
||||
break;
|
||||
case 'F':
|
||||
overlap_use_fullname = 1;
|
||||
break;
|
||||
case 'o':
|
||||
overlap_obj_level = 1;
|
||||
break;
|
||||
case 'h':
|
||||
overlap_hot_only = 1;
|
||||
break;
|
||||
case 't':
|
||||
overlap_hot_threshold = atof (optarg);
|
||||
break;
|
||||
default:
|
||||
overlap_usage ();
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind == 2)
|
||||
ret = profile_overlap (argv[optind], argv[optind+1]);
|
||||
else
|
||||
overlap_usage ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
|
||||
otherwise the output of --help. */
|
||||
|
||||
@ -383,6 +499,7 @@ print_usage (int error_p)
|
||||
fnotice (file, " -v, --version Print version number, then exit\n");
|
||||
print_merge_usage_message (error_p);
|
||||
print_rewrite_usage_message (error_p);
|
||||
print_overlap_usage_message (error_p);
|
||||
fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
|
||||
bug_report_url);
|
||||
exit (status);
|
||||
@ -471,6 +588,8 @@ main (int argc, char **argv)
|
||||
return do_merge (argc - optind, argv + optind);
|
||||
else if (!strcmp (sub_command, "rewrite"))
|
||||
return do_rewrite (argc - optind, argv + optind);
|
||||
else if (!strcmp (sub_command, "overlap"))
|
||||
return do_overlap (argc - optind, argv + optind);
|
||||
|
||||
print_usage (true);
|
||||
}
|
||||
|
@ -1,3 +1,20 @@
|
||||
2014-10-08 Rong Xu <xur@google.com>
|
||||
|
||||
* libgcov-util.c (read_gcda_file): Fix format.
|
||||
(find_match_gcov_info): Ditto.
|
||||
(calculate_2_entries): New.
|
||||
(compute_one_gcov): Ditto.
|
||||
(gcov_info_count_all_cold): Ditto.
|
||||
(gcov_info_count_all_zero): Ditto.
|
||||
(extract_file_basename): Ditto.
|
||||
(get_file_basename): Ditto.
|
||||
(set_flag): Ditto.
|
||||
(matched_gcov_info): Ditto.
|
||||
(calculate_overlap): Ditto.
|
||||
(gcov_profile_overlap): Ditto.
|
||||
* libgcov-driver.c (compute_summary): Make
|
||||
it avavilable for external calls.
|
||||
|
||||
2014-10-06 Rong Xu <xur@google.com>
|
||||
|
||||
* Makefile.in: Ditto.
|
||||
|
@ -274,7 +274,10 @@ static struct gcov_summary_buffer *sum_buffer;
|
||||
It computes and returns CRC32 and stored summary in THIS_PRG.
|
||||
Also determines the longest filename length of the info files. */
|
||||
|
||||
static gcov_unsigned_t
|
||||
#if !IN_GCOV_TOOL
|
||||
static
|
||||
#endif
|
||||
gcov_unsigned_t
|
||||
compute_summary (struct gcov_info *list, struct gcov_summary *this_prg,
|
||||
size_t *max_length)
|
||||
{
|
||||
|
@ -319,59 +319,59 @@ read_gcda_file (const char *filename)
|
||||
|
||||
tag = gcov_read_unsigned ();
|
||||
if (!tag)
|
||||
break;
|
||||
break;
|
||||
length = gcov_read_unsigned ();
|
||||
base = gcov_position ();
|
||||
mask = GCOV_TAG_MASK (tag) >> 1;
|
||||
for (tag_depth = 4; mask; mask >>= 8)
|
||||
{
|
||||
if (((mask & 0xff) != 0xff))
|
||||
{
|
||||
warning (0, "%s:tag `%x' is invalid\n", filename, tag);
|
||||
break;
|
||||
}
|
||||
tag_depth--;
|
||||
}
|
||||
{
|
||||
if (((mask & 0xff) != 0xff))
|
||||
{
|
||||
warning (0, "%s:tag `%x' is invalid\n", filename, tag);
|
||||
break;
|
||||
}
|
||||
tag_depth--;
|
||||
}
|
||||
for (format = tag_table; format->name; format++)
|
||||
if (format->tag == tag)
|
||||
goto found;
|
||||
if (format->tag == tag)
|
||||
goto found;
|
||||
format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1];
|
||||
found:;
|
||||
if (tag)
|
||||
{
|
||||
if (depth && depth < tag_depth)
|
||||
{
|
||||
if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
|
||||
warning (0, "%s:tag `%x' is incorrectly nested\n",
|
||||
filename, tag);
|
||||
}
|
||||
depth = tag_depth;
|
||||
tags[depth - 1] = tag;
|
||||
}
|
||||
{
|
||||
if (depth && depth < tag_depth)
|
||||
{
|
||||
if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag))
|
||||
warning (0, "%s:tag `%x' is incorrectly nested\n",
|
||||
filename, tag);
|
||||
}
|
||||
depth = tag_depth;
|
||||
tags[depth - 1] = tag;
|
||||
}
|
||||
|
||||
if (format->proc)
|
||||
{
|
||||
unsigned long actual_length;
|
||||
unsigned long actual_length;
|
||||
|
||||
(*format->proc) (tag, length);
|
||||
(*format->proc) (tag, length);
|
||||
|
||||
actual_length = gcov_position () - base;
|
||||
if (actual_length > length)
|
||||
warning (0, "%s:record size mismatch %lu bytes overread\n",
|
||||
filename, actual_length - length);
|
||||
else if (length > actual_length)
|
||||
warning (0, "%s:record size mismatch %lu bytes unread\n",
|
||||
filename, length - actual_length);
|
||||
}
|
||||
actual_length = gcov_position () - base;
|
||||
if (actual_length > length)
|
||||
warning (0, "%s:record size mismatch %lu bytes overread\n",
|
||||
filename, actual_length - length);
|
||||
else if (length > actual_length)
|
||||
warning (0, "%s:record size mismatch %lu bytes unread\n",
|
||||
filename, length - actual_length);
|
||||
}
|
||||
|
||||
gcov_sync (base, length);
|
||||
if ((error = gcov_is_error ()))
|
||||
{
|
||||
warning (0, error < 0 ? "%s:counter overflow at %lu\n" :
|
||||
"%s:read error at %lu\n", filename,
|
||||
(long unsigned) gcov_position ());
|
||||
break;
|
||||
}
|
||||
{
|
||||
warning (0, error < 0 ? "%s:counter overflow at %lu\n" :
|
||||
"%s:read error at %lu\n", filename,
|
||||
(long unsigned) gcov_position ());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
read_gcda_finalize (obj_info);
|
||||
@ -577,7 +577,8 @@ gcov_merge (struct gcov_info *info1, struct gcov_info *info2, int w)
|
||||
Return NULL if there is no match. */
|
||||
|
||||
static struct gcov_info *
|
||||
find_match_gcov_info (struct gcov_info **array, int size, struct gcov_info *info)
|
||||
find_match_gcov_info (struct gcov_info **array, int size,
|
||||
struct gcov_info *info)
|
||||
{
|
||||
struct gcov_info *gi_ptr;
|
||||
struct gcov_info *ret = NULL;
|
||||
@ -872,7 +873,530 @@ gcov_profile_normalize (struct gcov_info *profile, gcov_type max_val)
|
||||
|
||||
scale_factor = (float)max_val / curr_max_val;
|
||||
if (verbose)
|
||||
fnotice (stdout, "max_val is %lld\n", (long long) curr_max_val);
|
||||
fnotice (stdout, "max_val is %"PRId64"\n", curr_max_val);
|
||||
|
||||
return gcov_profile_scale (profile, scale_factor, 0, 0);
|
||||
}
|
||||
|
||||
/* The following variables are defined in gcc/gcov-tool.c. */
|
||||
extern int overlap_func_level;
|
||||
extern int overlap_obj_level;
|
||||
extern int overlap_hot_only;
|
||||
extern int overlap_use_fullname;
|
||||
extern double overlap_hot_threshold;
|
||||
|
||||
/* Compute the overlap score of two values. The score is defined as:
|
||||
min (V1/SUM_1, V2/SUM_2) */
|
||||
|
||||
static double
|
||||
calculate_2_entries (const unsigned long v1, const unsigned long v2,
|
||||
const double sum_1, const double sum_2)
|
||||
{
|
||||
double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1);
|
||||
double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2);
|
||||
|
||||
if (val2 < val1)
|
||||
val1 = val2;
|
||||
|
||||
return val1;
|
||||
}
|
||||
|
||||
/* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2.
|
||||
SUM_1 is the sum_all for profile1 where GCOV_INFO1 belongs.
|
||||
SUM_2 is the sum_all for profile2 where GCOV_INFO2 belongs.
|
||||
This function also updates cumulative score CUM_1_RESULT and
|
||||
CUM_2_RESULT. */
|
||||
|
||||
static double
|
||||
compute_one_gcov (const struct gcov_info *gcov_info1,
|
||||
const struct gcov_info *gcov_info2,
|
||||
const double sum_1, const double sum_2,
|
||||
double *cum_1_result, double *cum_2_result)
|
||||
{
|
||||
unsigned f_ix;
|
||||
double ret = 0;
|
||||
double cum_1 = 0, cum_2 = 0;
|
||||
const struct gcov_info *gcov_info = 0;
|
||||
double *cum_p;
|
||||
double sum;
|
||||
|
||||
gcc_assert (gcov_info1 || gcov_info2);
|
||||
if (!gcov_info1)
|
||||
{
|
||||
gcov_info = gcov_info2;
|
||||
cum_p = cum_2_result;
|
||||
sum = sum_2;
|
||||
*cum_1_result = 0;
|
||||
} else
|
||||
if (!gcov_info2)
|
||||
{
|
||||
gcov_info = gcov_info1;
|
||||
cum_p = cum_1_result;
|
||||
sum = sum_1;
|
||||
*cum_2_result = 0;
|
||||
}
|
||||
|
||||
if (gcov_info)
|
||||
{
|
||||
for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
|
||||
{
|
||||
unsigned t_ix;
|
||||
const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
|
||||
if (!gfi_ptr || gfi_ptr->key != gcov_info)
|
||||
continue;
|
||||
const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
|
||||
for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
|
||||
{
|
||||
unsigned c_num;
|
||||
|
||||
if (!gcov_info->merge[t_ix])
|
||||
continue;
|
||||
|
||||
for (c_num = 0; c_num < ci_ptr->num; c_num++)
|
||||
{
|
||||
cum_1 += ci_ptr->values[c_num] / sum;
|
||||
}
|
||||
ci_ptr++;
|
||||
}
|
||||
}
|
||||
*cum_p = cum_1;
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++)
|
||||
{
|
||||
unsigned t_ix;
|
||||
double func_cum_1 = 0.0;
|
||||
double func_cum_2 = 0.0;
|
||||
double func_val = 0.0;
|
||||
int nonzero = 0;
|
||||
int hot = 0;
|
||||
const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix];
|
||||
const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix];
|
||||
|
||||
if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1)
|
||||
continue;
|
||||
if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2)
|
||||
continue;
|
||||
|
||||
const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs;
|
||||
const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs;
|
||||
for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
|
||||
{
|
||||
unsigned c_num;
|
||||
|
||||
if (!gcov_info1->merge[t_ix])
|
||||
continue;
|
||||
|
||||
for (c_num = 0; c_num < ci_ptr1->num; c_num++)
|
||||
{
|
||||
if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num])
|
||||
{
|
||||
func_val += calculate_2_entries (ci_ptr1->values[c_num],
|
||||
ci_ptr2->values[c_num],
|
||||
sum_1, sum_2);
|
||||
|
||||
func_cum_1 += ci_ptr1->values[c_num] / sum_1;
|
||||
func_cum_2 += ci_ptr2->values[c_num] / sum_2;
|
||||
nonzero = 1;
|
||||
if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold ||
|
||||
ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold)
|
||||
hot = 1;
|
||||
}
|
||||
}
|
||||
ci_ptr1++;
|
||||
ci_ptr2++;
|
||||
}
|
||||
ret += func_val;
|
||||
cum_1 += func_cum_1;
|
||||
cum_2 += func_cum_2;
|
||||
if (overlap_func_level && nonzero && (!overlap_hot_only || hot))
|
||||
{
|
||||
printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n",
|
||||
gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100);
|
||||
}
|
||||
}
|
||||
*cum_1_result = cum_1;
|
||||
*cum_2_result = cum_2;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Test if all counter values in this GCOV_INFO are cold.
|
||||
"Cold" is defined as the counter value being less than
|
||||
or equal to THRESHOLD. */
|
||||
|
||||
static bool
|
||||
gcov_info_count_all_cold (const struct gcov_info *gcov_info,
|
||||
gcov_type threshold)
|
||||
{
|
||||
unsigned f_ix;
|
||||
|
||||
for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++)
|
||||
{
|
||||
unsigned t_ix;
|
||||
const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix];
|
||||
|
||||
if (!gfi_ptr || gfi_ptr->key != gcov_info)
|
||||
continue;
|
||||
const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs;
|
||||
for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++)
|
||||
{
|
||||
unsigned c_num;
|
||||
|
||||
if (!gcov_info->merge[t_ix])
|
||||
continue;
|
||||
|
||||
for (c_num = 0; c_num < ci_ptr->num; c_num++)
|
||||
{
|
||||
if (ci_ptr->values[c_num] > threshold)
|
||||
return false;
|
||||
}
|
||||
ci_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Test if all counter values in this GCOV_INFO are 0. */
|
||||
|
||||
static bool
|
||||
gcov_info_count_all_zero (const struct gcov_info *gcov_info)
|
||||
{
|
||||
return gcov_info_count_all_cold (gcov_info, 0);
|
||||
}
|
||||
|
||||
/* A pair of matched GCOV_INFO.
|
||||
The flag is a bitvector:
|
||||
b0: obj1's all counts are 0;
|
||||
b1: obj1's all counts are cold (but no 0);
|
||||
b2: obj1 is hot;
|
||||
b3: no obj1 to match obj2;
|
||||
b4: obj2's all counts are 0;
|
||||
b5: obj2's all counts are cold (but no 0);
|
||||
b6: obj2 is hot;
|
||||
b7: no obj2 to match obj1;
|
||||
*/
|
||||
struct overlap_t {
|
||||
const struct gcov_info *obj1;
|
||||
const struct gcov_info *obj2;
|
||||
char flag;
|
||||
};
|
||||
|
||||
#define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10))
|
||||
#define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20))
|
||||
#define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40))
|
||||
|
||||
/* Cumlative overlap dscore for profile1 and profile2. */
|
||||
static double overlap_sum_1, overlap_sum_2;
|
||||
|
||||
/* sum_all for profile1 and profile2. */
|
||||
static gcov_type p1_sum_all, p2_sum_all;
|
||||
|
||||
/* run_max for profile1 and profile2. */
|
||||
static gcov_type p1_run_max, p2_run_max;
|
||||
|
||||
/* The number of gcda files in the profiles. */
|
||||
static unsigned gcda_files[2];
|
||||
|
||||
/* The number of unique gcda files in the profiles
|
||||
(not existing in the other profile). */
|
||||
static unsigned unique_gcda_files[2];
|
||||
|
||||
/* The number of gcda files that all counter values are 0. */
|
||||
static unsigned zero_gcda_files[2];
|
||||
|
||||
/* The number of gcda files that all counter values are cold (but not 0). */
|
||||
static unsigned cold_gcda_files[2];
|
||||
|
||||
/* The number of gcda files that includes hot counter values. */
|
||||
static unsigned hot_gcda_files[2];
|
||||
|
||||
/* The number of gcda files with hot count value in either profiles. */
|
||||
static unsigned both_hot_cnt;
|
||||
|
||||
/* The number of gcda files with all counts cold (but not 0) in
|
||||
both profiles. */
|
||||
static unsigned both_cold_cnt;
|
||||
|
||||
/* The number of gcda files with all counts 0 in both profiles. */
|
||||
static unsigned both_zero_cnt;
|
||||
|
||||
/* Extract the basename of the filename NAME. */
|
||||
|
||||
static char *
|
||||
extract_file_basename (const char *name)
|
||||
{
|
||||
char *str;
|
||||
int len = 0;
|
||||
char *path = xstrdup (name);
|
||||
char sep_str[2];
|
||||
|
||||
sep_str[0] = DIR_SEPARATOR;
|
||||
sep_str[1] = 0;
|
||||
str = strstr(path, sep_str);
|
||||
do{
|
||||
len = strlen(str) + 1;
|
||||
path = &path[strlen(path) - len + 2];
|
||||
str = strstr(path, sep_str);
|
||||
} while(str);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/* Utility function to get the filename. */
|
||||
|
||||
static const char *
|
||||
get_file_basename (const char *name)
|
||||
{
|
||||
if (overlap_use_fullname)
|
||||
return name;
|
||||
return extract_file_basename (name);
|
||||
}
|
||||
|
||||
/* A utility function to set the flag for the gcda files. */
|
||||
|
||||
static void
|
||||
set_flag (struct overlap_t *e)
|
||||
{
|
||||
char flag = 0;
|
||||
|
||||
if (!e->obj1)
|
||||
{
|
||||
unique_gcda_files[1]++;
|
||||
flag = 0x8;
|
||||
}
|
||||
else
|
||||
{
|
||||
gcda_files[0]++;
|
||||
if (gcov_info_count_all_zero (e->obj1))
|
||||
{
|
||||
zero_gcda_files[0]++;
|
||||
flag = 0x1;
|
||||
}
|
||||
else
|
||||
if (gcov_info_count_all_cold (e->obj1, overlap_sum_1
|
||||
* overlap_hot_threshold))
|
||||
{
|
||||
cold_gcda_files[0]++;
|
||||
flag = 0x2;
|
||||
}
|
||||
else
|
||||
{
|
||||
hot_gcda_files[0]++;
|
||||
flag = 0x4;
|
||||
}
|
||||
}
|
||||
|
||||
if (!e->obj2)
|
||||
{
|
||||
unique_gcda_files[0]++;
|
||||
flag |= (0x8 << 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
gcda_files[1]++;
|
||||
if (gcov_info_count_all_zero (e->obj2))
|
||||
{
|
||||
zero_gcda_files[1]++;
|
||||
flag |= (0x1 << 4);
|
||||
}
|
||||
else
|
||||
if (gcov_info_count_all_cold (e->obj2, overlap_sum_2
|
||||
* overlap_hot_threshold))
|
||||
{
|
||||
cold_gcda_files[1]++;
|
||||
flag |= (0x2 << 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
hot_gcda_files[1]++;
|
||||
flag |= (0x4 << 4);
|
||||
}
|
||||
}
|
||||
|
||||
gcc_assert (flag);
|
||||
e->flag = flag;
|
||||
}
|
||||
|
||||
/* Test if INFO1 and INFO2 are from the matched source file.
|
||||
Return 1 if they match; return 0 otherwise. */
|
||||
|
||||
static int
|
||||
matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2)
|
||||
{
|
||||
/* For FDO, we have to match the name. This can be expensive.
|
||||
Maybe we should use hash here. */
|
||||
if (strcmp (info1->filename, info2->filename))
|
||||
return 0;
|
||||
|
||||
if (info1->n_functions != info2->n_functions)
|
||||
{
|
||||
fnotice (stderr, "mismatched profiles in %s (%d functions"
|
||||
" vs %d functions)\n",
|
||||
info1->filename,
|
||||
info1->n_functions,
|
||||
info2->n_functions);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Defined in libgcov-driver.c. */
|
||||
extern gcov_unsigned_t compute_summary (struct gcov_info *,
|
||||
struct gcov_summary *, size_t *);
|
||||
|
||||
/* Compute the overlap score of two profiles with the head of GCOV_LIST1 and
|
||||
GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no
|
||||
match and 1.0 meaning a perfect match. */
|
||||
|
||||
static double
|
||||
calculate_overlap (struct gcov_info *gcov_list1,
|
||||
struct gcov_info *gcov_list2)
|
||||
{
|
||||
struct gcov_summary this_prg;
|
||||
unsigned list1_cnt = 0, list2_cnt= 0, all_cnt;
|
||||
unsigned int i, j;
|
||||
size_t max_length;
|
||||
const struct gcov_info *gi_ptr;
|
||||
struct overlap_t *all_infos;
|
||||
|
||||
compute_summary (gcov_list1, &this_prg, &max_length);
|
||||
overlap_sum_1 = (double) (this_prg.ctrs[0].sum_all);
|
||||
p1_sum_all = this_prg.ctrs[0].sum_all;
|
||||
p1_run_max = this_prg.ctrs[0].run_max;
|
||||
compute_summary (gcov_list2, &this_prg, &max_length);
|
||||
overlap_sum_2 = (double) (this_prg.ctrs[0].sum_all);
|
||||
p2_sum_all = this_prg.ctrs[0].sum_all;
|
||||
p2_run_max = this_prg.ctrs[0].run_max;
|
||||
|
||||
for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next)
|
||||
list1_cnt++;
|
||||
for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next)
|
||||
list2_cnt++;
|
||||
all_cnt = list1_cnt + list2_cnt;
|
||||
all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t)
|
||||
* all_cnt * 2);
|
||||
gcc_assert (all_infos);
|
||||
|
||||
i = 0;
|
||||
for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++)
|
||||
{
|
||||
all_infos[i].obj1 = gi_ptr;
|
||||
all_infos[i].obj2 = 0;
|
||||
}
|
||||
|
||||
for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++)
|
||||
{
|
||||
all_infos[i].obj1 = 0;
|
||||
all_infos[i].obj2 = gi_ptr;
|
||||
}
|
||||
|
||||
for (i = list1_cnt; i < all_cnt; i++)
|
||||
{
|
||||
if (all_infos[i].obj2 == 0)
|
||||
continue;
|
||||
for (j = 0; j < list1_cnt; j++)
|
||||
{
|
||||
if (all_infos[j].obj2 != 0)
|
||||
continue;
|
||||
if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1))
|
||||
{
|
||||
all_infos[j].obj2 = all_infos[i].obj2;
|
||||
all_infos[i].obj2 = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < all_cnt; i++)
|
||||
if (all_infos[i].obj1 || all_infos[i].obj2)
|
||||
{
|
||||
set_flag (all_infos + i);
|
||||
if (FLAG_ONE_HOT (all_infos[i].flag))
|
||||
both_hot_cnt++;
|
||||
if (FLAG_BOTH_COLD(all_infos[i].flag))
|
||||
both_cold_cnt++;
|
||||
if (FLAG_BOTH_ZERO(all_infos[i].flag))
|
||||
both_zero_cnt++;
|
||||
}
|
||||
|
||||
double prg_val = 0;
|
||||
double sum_val = 0;
|
||||
double sum_cum_1 = 0;
|
||||
double sum_cum_2 = 0;
|
||||
|
||||
for (i = 0; i < all_cnt; i++)
|
||||
{
|
||||
double val;
|
||||
double cum_1, cum_2;
|
||||
const char *filename;
|
||||
|
||||
if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0)
|
||||
continue;
|
||||
if (FLAG_BOTH_ZERO (all_infos[i].flag))
|
||||
continue;
|
||||
|
||||
if (all_infos[i].obj1)
|
||||
filename = get_file_basename (all_infos[i].obj1->filename);
|
||||
else
|
||||
filename = get_file_basename (all_infos[i].obj2->filename);
|
||||
|
||||
if (overlap_func_level)
|
||||
printf("\n processing %36s:\n", filename);
|
||||
|
||||
val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2,
|
||||
overlap_sum_1, overlap_sum_2, &cum_1, &cum_2);
|
||||
|
||||
if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag)))
|
||||
{
|
||||
printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
|
||||
filename, val*100, cum_1*100, cum_2*100);
|
||||
sum_val += val;
|
||||
sum_cum_1 += cum_1;
|
||||
sum_cum_2 += cum_2;
|
||||
}
|
||||
|
||||
prg_val += val;
|
||||
|
||||
}
|
||||
|
||||
if (overlap_obj_level)
|
||||
printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n",
|
||||
"", sum_val*100, sum_cum_1*100, sum_cum_2*100);
|
||||
|
||||
printf (" Statistics:\n"
|
||||
" profile1_# profile2_# overlap_#\n");
|
||||
printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1],
|
||||
gcda_files[0]-unique_gcda_files[0]);
|
||||
printf (" unique files: %12u\t%12u\n", unique_gcda_files[0],
|
||||
unique_gcda_files[1]);
|
||||
printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0],
|
||||
hot_gcda_files[1], both_hot_cnt);
|
||||
printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0],
|
||||
cold_gcda_files[1], both_cold_cnt);
|
||||
printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0],
|
||||
zero_gcda_files[1], both_zero_cnt);
|
||||
printf (" sum_all: %12"PRId64"\t%12"PRId64"\n", p1_sum_all, p2_sum_all);
|
||||
printf (" run_max: %12"PRId64"\t%12"PRId64"\n", p1_run_max, p2_run_max);
|
||||
|
||||
return prg_val;
|
||||
}
|
||||
|
||||
/* Computer the overlap score of two lists of gcov_info objects PROFILE1 and PROFILE2.
|
||||
Return 0 on success: without mismatch. Reutrn 1 on error. */
|
||||
|
||||
int
|
||||
gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2)
|
||||
{
|
||||
double result;
|
||||
|
||||
result = calculate_overlap (profile1, profile2);
|
||||
|
||||
if (result > 0)
|
||||
{
|
||||
printf("\nProgram level overlap result is %3.2f%%\n\n", result*100);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user