From patchwork Mon Apr 25 07:09:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Huber X-Patchwork-Id: 1621734 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by bilbo.ozlabs.org (Postfix) with ESMTPS id 4Kmx5c0rCkz9s07 for ; Mon, 25 Apr 2022 17:11:48 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 03C643857C4D for ; Mon, 25 Apr 2022 07:11:46 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from dedi548.your-server.de (dedi548.your-server.de [85.10.215.148]) by sourceware.org (Postfix) with ESMTPS id AAD58385840C for ; Mon, 25 Apr 2022 07:09:35 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org AAD58385840C Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embedded-brains.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embedded-brains.de Received: from sslproxy05.your-server.de ([78.46.172.2]) by dedi548.your-server.de with esmtpsa (TLS1.3) tls TLS_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1nisqk-0004mn-HN; Mon, 25 Apr 2022 09:09:34 +0200 Received: from [82.100.198.138] (helo=mail.embedded-brains.de) by sslproxy05.your-server.de with esmtpsa (TLSv1.3:TLS_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1nisqk-000X9Y-Ei; Mon, 25 Apr 2022 09:09:34 +0200 Received: from localhost (localhost [127.0.0.1]) by mail.embedded-brains.de (Postfix) with ESMTP id 286624800CA; Mon, 25 Apr 2022 09:09:34 +0200 (CEST) Received: from mail.embedded-brains.de ([127.0.0.1]) by localhost (zimbra.eb.localhost [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id aR21VoFZz6xI; Mon, 25 Apr 2022 09:09:33 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by mail.embedded-brains.de (Postfix) with ESMTP id 8A5A64801EA; Mon, 25 Apr 2022 09:09:33 +0200 (CEST) X-Virus-Scanned: amavisd-new at zimbra.eb.localhost Received: from mail.embedded-brains.de ([127.0.0.1]) by localhost (zimbra.eb.localhost [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id Qi2LqVi4QYLq; Mon, 25 Apr 2022 09:09:33 +0200 (CEST) Received: from zimbra.eb.localhost (unknown [192.168.96.242]) by mail.embedded-brains.de (Postfix) with ESMTPSA id 681104801EB; Mon, 25 Apr 2022 09:09:33 +0200 (CEST) From: Sebastian Huber To: gcc-patches@gcc.gnu.org Subject: [gcov v2 12/14] gcov-tool: Add merge-stream subcommand Date: Mon, 25 Apr 2022 09:09:27 +0200 Message-Id: <20220425070929.7466-13-sebastian.huber@embedded-brains.de> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20220425070929.7466-1-sebastian.huber@embedded-brains.de> References: <20220425070929.7466-1-sebastian.huber@embedded-brains.de> MIME-Version: 1.0 X-Authenticated-Sender: smtp-embedded@poldinet.de X-Virus-Scanned: Clear (ClamAV 0.103.5/26522/Sun Apr 24 10:22:35 2022) X-Spam-Status: No, score=-11.1 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" 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. --- gcc/doc/gcov-tool.texi | 36 ++++++++++++++++ gcc/doc/invoke.texi | 5 +++ gcc/gcov-tool.cc | 76 +++++++++++++++++++++++++++++++++ libgcc/libgcov-util.c | 95 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 212 insertions(+) diff --git a/gcc/doc/gcov-tool.texi b/gcc/doc/gcov-tool.texi index d79dbc94a8c..77150836acc 100644 --- a/gcc/doc/gcov-tool.texi +++ b/gcc/doc/gcov-tool.texi @@ -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 }. +@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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index af5495e75c6..cef0fa9f084 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 diff --git a/gcc/gcov-tool.cc b/gcc/gcov-tool.cc index d712715cf7e..ceb250143c8 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] [] Merge coverage stream file (or stdin)\n" + " and coverage file contents\n"); + fnotice (file, " -v, --verbose Verbose mode\n"); + fnotice (file, " -w, --weight 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 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. */