[RFC/gcov,12/12] gcov-tool: Add merge-stream subcommand
Commit Message
gcc/
* 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.
---
gcc/gcov-tool.cc | 76 ++++++++++++++++++++++++++++++++++++++++
libgcc/libgcov-util.c | 80 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 156 insertions(+)
Comments
On 3/31/22 13:35, Sebastian Huber wrote:
> gcc/
>
> * 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.
> ---
> gcc/gcov-tool.cc | 76 ++++++++++++++++++++++++++++++++++++++++
> libgcc/libgcov-util.c | 80 +++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 156 insertions(+)
>
> diff --git a/gcc/gcov-tool.cc b/gcc/gcov-tool.cc
> index d712715cf7e..d8572b184e9 100644
> --- a/gcc/gcov-tool.cc
> +++ b/gcc/gcov-tool.cc
> @@ -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] [stream-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"))
> diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c
> index 622d5a9dc71..0fe60528b48 100644
> --- a/libgcc/libgcov-util.c
> +++ b/libgcc/libgcov-util.c
> @@ -735,6 +735,86 @@ gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile
> return tgt_profile;
> }
Please document the new added functions below.
>
> +struct gcov_info *
> +consume_stream (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)
A space after ().
Martin
> + 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;
> +}
> +
> +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;
> +}
> +
> +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 = consume_stream (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. */
@@ -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] [stream-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,86 @@ gcov_profile_merge (struct gcov_info *tgt_profile, struct gcov_info *src_profile
return tgt_profile;
}
+struct gcov_info *
+consume_stream (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;
+}
+
+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;
+}
+
+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 = consume_stream (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. */