gcov-tool: Add merge-stream subcommand
gcc/ * doc/gcov-tool.texi: Document merge-stream subcommand. * doc/invoke.texi (fprofile-info-section): Mention merge-stream subcommand of gcov-tool. * gcov-tool.cc (gcov_profile_merge_stream): Declare. (print_merge_stream_usage_message): New. (merge_stream_usage): Likewise. (do_merge_stream): Likewise. (print_usage): Call print_merge_stream_usage_message(). (main): Call do_merge_stream() to execute merge-stream subcommand. libgcc/ * libgcov-util.c (consume_stream): New. (get_target_profiles_for_merge): Likewise. (gcov_profile_merge_stream): Likewise.
This commit is contained in:
parent
ef9a53feae
commit
210e32b60b
|
@ -52,6 +52,10 @@ Current gcov-tool supports the following functionalities:
|
|||
@item
|
||||
merge two sets of profiles with weights.
|
||||
|
||||
@item
|
||||
read a stream of profiles with associated filenames and merge it with a set of
|
||||
profiles with weights.
|
||||
|
||||
@item
|
||||
read one set of profile and rewrite profile contents. One can scale or
|
||||
normalize the count values.
|
||||
|
@ -64,6 +68,12 @@ Collect the profiles for different set of inputs, and use this tool to merge
|
|||
them. One can specify the weight to factor in the relative importance of
|
||||
each input.
|
||||
|
||||
@item
|
||||
Collect profiles from target systems without a filesystem (freestanding
|
||||
environments). Merge the collected profiles with associated profiles
|
||||
present on the host system. One can specify the weight to factor in the
|
||||
relative importance of each input.
|
||||
|
||||
@item
|
||||
Rewrite the profile after removing a subset of the gcda files, while maintaining
|
||||
the consistency of the summary and the histogram.
|
||||
|
@ -117,6 +127,10 @@ gcov-tool merge [merge-options] @var{directory1} @var{directory2}
|
|||
[@option{-v}|@option{--verbose}]
|
||||
[@option{-w}|@option{--weight} @var{w1,w2}]
|
||||
|
||||
gcov-tool merge-stream [merge-stream-options] [@var{file}]
|
||||
[@option{-v}|@option{--verbose}]
|
||||
[@option{-w}|@option{--weight} @var{w1,w2}]
|
||||
|
||||
gcov-tool rewrite [rewrite-options] @var{directory}
|
||||
[@option{-n}|@option{--normalize} @var{long_long_value}]
|
||||
[@option{-o}|@option{--output} @var{directory}]
|
||||
|
@ -169,6 +183,28 @@ Set the merge weights of the @var{directory1} and @var{directory2},
|
|||
respectively. The default weights are 1 for both.
|
||||
@end table
|
||||
|
||||
@item merge-stream
|
||||
Collect profiles with associated filenames from a @emph{gcfn} and @emph{gcda}
|
||||
data stream. Read the stream from the file specified by @var{file} or from
|
||||
@file{stdin}. Merge the profiles with associated profiles in the host
|
||||
filesystem. Apply the optional weights while merging profiles.
|
||||
|
||||
For the generation of a @emph{gcfn} and @emph{gcda} data stream on the target
|
||||
system, please have a look at the @code{__gcov_filename_to_gcfn()} and
|
||||
@code{__gcov_info_to_gcda()} functions declared in @code{#include <gcov.h>}.
|
||||
@table @gcctabopt
|
||||
|
||||
@item -v
|
||||
@itemx --verbose
|
||||
Set the verbose mode.
|
||||
|
||||
@item -w @var{w1},@var{w2}
|
||||
@itemx --weight @var{w1},@var{w2}
|
||||
Set the merge weights of the profiles from the @emph{gcfn} and @emph{gcda} data
|
||||
stream and the associated profiles in the host filesystem, respectively. The
|
||||
default weights are 1 for both.
|
||||
@end table
|
||||
|
||||
@item rewrite
|
||||
Read the specified profile directory and rewrite to a new directory.
|
||||
@table @gcctabopt
|
||||
|
|
|
@ -15537,6 +15537,11 @@ main (void)
|
|||
@}
|
||||
@end smallexample
|
||||
|
||||
The @command{merge-stream} subcommand of @command{gcov-tool} may be used to
|
||||
deserialize the data stream generated by the @code{__gcov_filename_to_gcfn} and
|
||||
@code{__gcov_info_to_gcda} functions and merge the profile information into
|
||||
@file{.gcda} files on the host filesystem.
|
||||
|
||||
@item -fprofile-note=@var{path}
|
||||
@opindex fprofile-note
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|||
|
||||
extern struct gcov_info *gcov_profile_merge (struct gcov_info*,
|
||||
struct gcov_info*, int, int);
|
||||
extern struct gcov_info *gcov_profile_merge_stream (const char *, 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);
|
||||
|
@ -229,6 +230,78 @@ do_merge (int argc, char **argv)
|
|||
return profile_merge (argv[optind], argv[optind+1], output_dir, w1, w2);
|
||||
}
|
||||
|
||||
/* Usage message for profile merge-stream. */
|
||||
|
||||
static void
|
||||
print_merge_stream_usage_message (int error_p)
|
||||
{
|
||||
FILE *file = error_p ? stderr : stdout;
|
||||
|
||||
fnotice (file, " merge-stream [options] [<file>] Merge coverage stream file (or stdin)\n"
|
||||
" and coverage file contents\n");
|
||||
fnotice (file, " -v, --verbose Verbose mode\n");
|
||||
fnotice (file, " -w, --weight <w1,w2> Set weights (float point values)\n");
|
||||
}
|
||||
|
||||
static const struct option merge_stream_options[] =
|
||||
{
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "weight", required_argument, NULL, 'w' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/* Print merge-stream usage and exit. */
|
||||
|
||||
static void ATTRIBUTE_NORETURN
|
||||
merge_stream_usage (void)
|
||||
{
|
||||
fnotice (stderr, "Merge-stream subcomand usage:");
|
||||
print_merge_stream_usage_message (true);
|
||||
exit (FATAL_EXIT_CODE);
|
||||
}
|
||||
|
||||
/* Driver for profile merge-stream sub-command. */
|
||||
|
||||
static int
|
||||
do_merge_stream (int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
int w1 = 1, w2 = 1;
|
||||
struct gcov_info *merged_profile;
|
||||
|
||||
optind = 0;
|
||||
while ((opt = getopt_long (argc, argv, "vw:",
|
||||
merge_stream_options, NULL)) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'v':
|
||||
verbose = true;
|
||||
gcov_set_verbose ();
|
||||
break;
|
||||
case 'w':
|
||||
sscanf (optarg, "%d,%d", &w1, &w2);
|
||||
if (w1 < 0 || w2 < 0)
|
||||
fatal_error (input_location, "weights need to be non-negative");
|
||||
break;
|
||||
default:
|
||||
merge_stream_usage ();
|
||||
}
|
||||
}
|
||||
|
||||
if (argc - optind > 1)
|
||||
merge_stream_usage ();
|
||||
|
||||
merged_profile = gcov_profile_merge_stream (argv[optind], w1, w2);
|
||||
|
||||
if (merged_profile)
|
||||
gcov_do_dump (merged_profile, 0, -1);
|
||||
else if (verbose)
|
||||
fnotice (stdout, "no profile files were merged\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If N_VAL is no-zero, normalize the profile by setting the largest counter
|
||||
counter value to N_VAL and scale others counters proportionally.
|
||||
Otherwise, multiply the all counters by SCALE. */
|
||||
|
@ -505,6 +578,7 @@ print_usage (int error_p)
|
|||
fnotice (file, " -h, --help Print this help, then exit\n");
|
||||
fnotice (file, " -v, --version Print version number, then exit\n");
|
||||
print_merge_usage_message (error_p);
|
||||
print_merge_stream_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",
|
||||
|
@ -594,6 +668,8 @@ main (int argc, char **argv)
|
|||
|
||||
if (!strcmp (sub_command, "merge"))
|
||||
return do_merge (argc - optind, argv + optind);
|
||||
else if (!strcmp (sub_command, "merge-stream"))
|
||||
return do_merge_stream (argc - optind, argv + optind);
|
||||
else if (!strcmp (sub_command, "rewrite"))
|
||||
return do_rewrite (argc - optind, argv + optind);
|
||||
else if (!strcmp (sub_command, "overlap"))
|
||||
|
|
|
@ -735,6 +735,101 @@ gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile
|
|||
return tgt_profile;
|
||||
}
|
||||
|
||||
/* Deserialize gcov_info objects and associated filenames from the file
|
||||
specified by FILENAME to create a profile list. When FILENAME is NULL, read
|
||||
from stdin. Return the profile list. */
|
||||
|
||||
struct gcov_info *
|
||||
deserialize_profiles (const char *filename)
|
||||
{
|
||||
read_profile_dir_init ();
|
||||
|
||||
while (true)
|
||||
{
|
||||
unsigned version;
|
||||
const char *filename_of_info;
|
||||
struct gcov_info *obj_info;
|
||||
|
||||
if (!gcov_magic (gcov_read_unsigned (), GCOV_FILENAME_MAGIC))
|
||||
{
|
||||
if (gcov_is_error () != 2)
|
||||
fnotice (stderr, "%s:not a gcfn stream\n", filename);
|
||||
break;
|
||||
}
|
||||
|
||||
version = gcov_read_unsigned ();
|
||||
if (version != GCOV_VERSION)
|
||||
{
|
||||
fnotice (stderr, "%s:incorrect gcov version %d vs %d \n",
|
||||
filename, version, GCOV_VERSION);
|
||||
break;
|
||||
}
|
||||
|
||||
filename_of_info = gcov_read_string ();
|
||||
if (!filename_of_info)
|
||||
{
|
||||
fnotice (stderr, "%s:no filename in gcfn stream\n",
|
||||
filename);
|
||||
break;
|
||||
}
|
||||
|
||||
obj_info = read_gcda_file (filename);
|
||||
if (!obj_info)
|
||||
break;
|
||||
|
||||
obj_info->filename = filename_of_info;
|
||||
}
|
||||
|
||||
return gcov_info_head;
|
||||
}
|
||||
|
||||
/* For each profile of the list specified by SRC_PROFILE, read the GCDA file of
|
||||
the profile. If a GCDA file exists, add the profile to a list. Return the
|
||||
profile list. */
|
||||
|
||||
struct gcov_info *
|
||||
get_target_profiles_for_merge (struct gcov_info *src_profile)
|
||||
{
|
||||
struct gcov_info *gi_ptr;
|
||||
|
||||
read_profile_dir_init ();
|
||||
|
||||
for (gi_ptr = src_profile; gi_ptr; gi_ptr = gi_ptr->next)
|
||||
if (gcov_open (gi_ptr->filename, 1))
|
||||
{
|
||||
(void)read_gcda_file (gi_ptr->filename);
|
||||
gcov_close ();
|
||||
}
|
||||
|
||||
return gcov_info_head;
|
||||
}
|
||||
|
||||
/* Deserialize gcov_info objects and associated filenames from the file
|
||||
specified by FILENAME to create a source profile list. When FILENAME is
|
||||
NULL, read from stdin. Use the filenames of the source profile list to get
|
||||
a target profile list. Merge the source profile list into the target
|
||||
profile list using weights W1 and W2. Return the list of merged gcov_info
|
||||
objects. Return NULL if the list is empty. */
|
||||
|
||||
struct gcov_info *
|
||||
gcov_profile_merge_stream (const char *filename, int w1, int w2)
|
||||
{
|
||||
struct gcov_info *tgt_profile;
|
||||
struct gcov_info *src_profile;
|
||||
|
||||
if (!gcov_open (filename, 1))
|
||||
{
|
||||
fnotice (stderr, "%s:cannot open\n", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
src_profile = deserialize_profiles (filename ? filename : "<stdin>");
|
||||
gcov_close ();
|
||||
tgt_profile = get_target_profiles_for_merge (src_profile);
|
||||
|
||||
return gcov_profile_merge (tgt_profile, src_profile, w1, w2);
|
||||
}
|
||||
|
||||
typedef gcov_type (*counter_op_fn) (gcov_type, void*, void*);
|
||||
|
||||
/* Performing FN upon arc counters. */
|
||||
|
|
Loading…
Reference in New Issue