From 210e32b60b9018e5db2d9741dc7aaa5d9b436999 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Wed, 30 Mar 2022 16:53:29 +0200 Subject: 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. --- libgcc/libgcov-util.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) (limited to 'libgcc') diff --git a/libgcc/libgcov-util.c b/libgcc/libgcov-util.c index bf96f508db0..250dddd8e21 100644 --- a/libgcc/libgcov-util.c +++ b/libgcc/libgcov-util.c @@ -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 : ""); + 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. */ -- cgit v1.2.3