@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.
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.
[@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}]
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
@}
@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
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);
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. */
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",
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"))
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. */