From patchwork Tue Feb 4 18:59:20 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rong Xu X-Patchwork-Id: 316720 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 74EDB2C0081 for ; Wed, 5 Feb 2014 05:59:39 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:in-reply-to:references:date:message-id:subject :from:to:cc:content-type; q=dns; s=default; b=crMSvghrobaZQlJf0h G3vCPpvYQV2ZlQQAYyJbHn/8WnL7zznPgPQpiF+a39AOOY4j9jZOfjmSmMPv0bD7 0ghu8Nl2Ts5/ENV/G8nHenj7jBC1FxgM74/fTU04Kyhf4WKZjfiRFjCk+1lSv+kC Jc3PNvRIZLZZZDU3OP6wBBBWc= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:in-reply-to:references:date:message-id:subject :from:to:cc:content-type; s=default; bh=r310vFR7SZTwkxVnX8xfp9Zt Tx0=; b=qY9vGGyw3KdFH2bryXDR2rv94ItCuvjnDHE5hKz6TTPm4GZ0V+Pn0u+B x3hOiCfGTJChxpCqS3iTckgirJvW4ETz/zZASfKe4QxaC5WroR2fei0anERu8lvH kkAiniDbLnmvT4nTEjkVJX2uhr6elL3mw9NP3ygTB+uBn6RX1GQ= Received: (qmail 9240 invoked by alias); 4 Feb 2014 18:59:31 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 9226 invoked by uid 89); 4 Feb 2014 18:59:30 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-2.1 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 X-HELO: mail-oa0-f41.google.com Received: from mail-oa0-f41.google.com (HELO mail-oa0-f41.google.com) (209.85.219.41) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Tue, 04 Feb 2014 18:59:22 +0000 Received: by mail-oa0-f41.google.com with SMTP id j17so10319187oag.14 for ; Tue, 04 Feb 2014 10:59:20 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:date :message-id:subject:from:to:cc:content-type; bh=6JjPhsi+bimxldLxAhYwDCu87HCM9yl3PBUVzElvo/Q=; b=fQ/ej2qHzdCsDxVhh/WfpFWWzV9sm1mxVWrP2Wo4qFfUEkQ4enNMvqxWHOxntaN4sc xYS20KnmopCj8ISv4WuKkaqhIPEEMjIZhVFV3wWAJz3XZI5kO7zaEDnQMQIc3QpOn6YW 3LNu+d2BdHadL/0gTFaASiv6oenfBB+RmpYYO85SifL49qSAEZXw0X3EtnDgbmkzVRAg +Phxbh/wrN8BJFHjM9Rp352wptV+1J2xzM5d+CJRRAaypZjTjUlypFSGYtwjZwlSdm2b LsuVStJk5JTnBkYUQuNX056QZzpTcypZXsBlPKqZzz6FXHgpe2fZQE5SNC+fwoMDFYSp rRMQ== X-Gm-Message-State: ALoCoQmfO3ShgReMCB2pSlZyWsdDdPVWOBvS8pK50eEZ2uE9m948m/LoXRZ7esbSVLlzq378ndy8SuMJMdGZ6m9WKTvmteHltb5lwwsSkSu/bzw+R1+mbW31hxzFo3j50wPh+x5IU+ovYdkbXVObTmnxXCdJ7Fofi+PkYT2H8OoiZU1nibVH3V+q2CMSUWsWhr7GdYL/hhUWbztbF2XmLgLGNaFCIdDD3w== MIME-Version: 1.0 X-Received: by 10.60.119.40 with SMTP id kr8mr3318066oeb.66.1391540360565; Tue, 04 Feb 2014 10:59:20 -0800 (PST) Received: by 10.182.195.20 with HTTP; Tue, 4 Feb 2014 10:59:20 -0800 (PST) In-Reply-To: References: Date: Tue, 4 Feb 2014 10:59:20 -0800 Message-ID: Subject: Re: [google gcc-4_8] gcov-tool: some new LIPO supports. From: Rong Xu To: Xinliang David Li Cc: GCC Patches , Teresa Johnson X-IsSubscribed: yes Here is the revised patch that integrates Teresa' comments. Ok for checking in? -Rong On Thu, Jan 30, 2014 at 1:20 PM, Rong Xu wrote: > Comments are inlined. New patch attached to this email. > > -Rong > > On Thu, Jan 30, 2014 at 12:39 PM, Xinliang David Li wrote: >> On Wed, Jan 29, 2014 at 4:24 PM, Rong Xu wrote: >>> Hi, >>> >>> The attached patch adds some new features to gcov-tool. It aims to >>> rewrite LIPO profile for reuse, debug or performance tuning purpose. >>> >>> -l, --modu_list Only use the modules in this file >> >> I think in verbose mode, the tool should emit warnings when a module >> is trimmed due to this option. This can be used in regression test. >> > > In previous patch, this warning is emitted unconventionally (not > guarded by verbose flag). > I changed it to under verbose mode in this patch. > >>> -r, --string Replace string in path >> >> --path_substr_replace or something in that line. >> > > Done. > >>> -u, --use_imports_file Use the grouping in import files. >>> >> >> Is there a path in code to auto test this? > > As we discussed offline. This can be verified by a separated script. > >> >>> -l uses only the modules in specified file to compute module grouping >>> (and subsequent dumping). >>> -r replaces the pattern specified in the argument. The format is: >>> old_str1:new_str1[,old_str2:new_str2]*, only the first occurrence is >>> replaced. >>> -u skips the run-time module grouping computation and reuses the one >>> comes with the profiles (which is user editable). >>> >>> Tested with profiles from google internal benchmarks. >>> >> >> Also use strcasestr for case insenstive operation. > > Done. > >> >> David >> >>> -Rong Index: gcc/gcov-tool.c =================================================================== --- gcc/gcov-tool.c (revision 207435) +++ gcc/gcov-tool.c (working copy) @@ -29,6 +29,7 @@ see the files COPYING3 and COPYING.RUNTIME respect #include "coretypes.h" #include "tm.h" #include "intl.h" +#include "hashtab.h" #include "diagnostic.h" #include "version.h" #include "gcov-io.h" @@ -38,6 +39,7 @@ see the files COPYING3 and COPYING.RUNTIME respect #include #include #include "params.h" +#include extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int); extern int gcov_profile_normalize (struct gcov_info*, gcov_type); @@ -47,9 +49,11 @@ extern struct gcov_info* gcov_read_profile_dir (co extern void gcov_exit (void); extern void set_gcov_list (struct gcov_info *); extern void gcov_set_verbose (void); +extern void set_use_existing_grouping (void); +extern void set_use_modu_list (void); +extern void lipo_set_substitute_string (const char *); -static int verbose; - +/* The following defines are needed by dyn-ipa.c. */ gcov_unsigned_t __gcov_lipo_grouping_algorithm; gcov_unsigned_t __gcov_lipo_merge_modu_edges; gcov_unsigned_t __gcov_lipo_weak_inclusion; @@ -60,6 +64,8 @@ gcov_unsigned_t __gcov_lipo_random_seed; gcov_unsigned_t __gcov_lipo_dump_cgraph; gcov_unsigned_t __gcov_lipo_propagate_scale; +static int verbose; + /* Remove file NAME if it has a gcda suffix. */ static int @@ -285,6 +291,189 @@ profile_rewrite (const char *d1, const char *out, return 0; } +/* This is the hashtab entry to store a name and mod_id pair. */ +typedef struct { + const char *name; + unsigned id; +} mod_name_id; + +/* Hash and comparison functions for strings. */ + +static unsigned +mod_name_id_htab_hash (const void *s_p) +{ + const char *s = ((const mod_name_id *) s_p)->name; + return (*htab_hash_string) (s); +} + +static int +mod_name_id_hash_eq (const void *s1_p, const void *s2_p) +{ + return strcmp (((const mod_name_id *) s1_p)->name, + ((const mod_name_id *) s2_p)->name) == 0; +} + +static htab_t mod_name_id_hash_table; + +/* Look up an entry in the hash table. STRING is the module name. + CREATE controls to insert to htab or not. + If (*ID_P != 0), we write (*ID_P) to htab. + If (*ID_P == 0), we write module_id to (*ID_P). + return 1 if an entry is found and otherwise 0. */ + +static int +module_name_hash_lookup (const char *string, unsigned *id_p, int create) +{ + void **e; + mod_name_id t; + + t.name = string; + e = htab_find_slot (mod_name_id_hash_table, &t, + create ? INSERT : NO_INSERT); + if (e == NULL) + return 0; + if (*e == NULL) + { + *e = XNEW (mod_name_id *); + (*(mod_name_id **)e)->name = xstrdup (string); + } + if (id_p) + { + if (*id_p != 0) + (*(mod_name_id **)e)->id = *id_p; + else + *id_p = (*(mod_name_id **)e)->id; + } + return 1; +} + +/* Return 1 if NAME is of a source type that LIPO targets. + Return 0 otherwise. */ + +static int +is_lipo_source_type (char *name) +{ + char *p; + + if (strcasestr (name, ".c") || + strcasestr (name, ".cc") || + strcasestr (name, ".cpp") || + strcasestr (name, ".c++")) + return 1; + + /* Replace ".proto" with ".pb.cc". Since the two strings have the same + length, we simplfy do a strcpy. */ + if ((p = strcasestr (name, ".proto")) != NULL) + { + strcpy (p, ".pb.cc"); + return 1; + } + + return 0; +} + +/* Convert/process the names from dependence query to a + stardard format. Return NULL if this is not a lipo + target source. */ + +static char * +lipo_process_name_string (char *name) +{ + char *p; + + if (name == NULL) + return NULL; + if (strlen (name) == 0) + return NULL; + + if (!is_lipo_source_type (name)) + return NULL; + + /* Overwrite ':' with '/'. */ + if ((p = strchr (name, ':')) != NULL) + *p = '/'; + + /* Remove "//". */ + if (name[0] == '/' && name[1] =='/') + name += 2; + + return name; +} + +/* Store the list of source modules in INPUT_FILE to internal hashtab. */ + +static int +lipo_process_modu_list (const char *input_file) +{ + FILE *fd; + char *line = NULL; + size_t linecap = 0; + char *name; + + set_use_modu_list (); + + if ((fd = fopen (input_file, "r")) == NULL) + { + fnotice (stderr, "Cannot open %s\n", input_file); + return -1; + } + + /* Read all the modules */ + while (getline (&line, &linecap, fd) != -1) + { + name = strtok (line, " \t\n"); + name = lipo_process_name_string (name); + if (name) + module_name_hash_lookup (name, 0, 1); + + free (line); + line = NULL; + } + + return 0; +} + +#define GENFILE_PREFIX "/genfiles/" + +/* Return 1 if module NAME is available to be used in the target + profile. CREATE controls to insert to htab or not. + If (*ID_P != 0), we write (*ID_P) to htab. + If (*ID_P == 0), we write module_id to (*ID_P). + return 1 if an entry is found and otherwise 0. */ + +int +is_module_available (const char *name, unsigned *id_p, int create) +{ + char *buf, *p; + int ret; + + if (mod_name_id_hash_table == NULL) + return 1; + + buf = xstrdup (name); + /* Remove genfile string. */ + if ((p = strstr (buf, GENFILE_PREFIX)) != NULL) + p += strlen (GENFILE_PREFIX); + else + p = buf; + + ret = module_name_hash_lookup (p, id_p, create); + free (buf); + return ret; +} + +/* Return module_ident for module NAME. + return 0 if the module NAME is not available. */ + +int +get_module_id_from_name (const char *name) +{ + unsigned mod_id = 0; + if (is_module_available (name, &mod_id, 0) == 1) + return mod_id; + return 0; +} + /* Usage function for profile rewrite. */ static void @@ -295,7 +484,10 @@ print_rewrite_usage_message (int error_p) fnotice (file, " rewrite [options] Rewrite coverage file contents\n"); fnotice (file, " -v, --verbose Verbose mode\n"); fnotice (file, " -o, --output Output directory\n"); + fnotice (file, " -l, --modu_list Only use the modules in this file\n"); + fnotice (file, " -r, --path_substr_replace Replace string in path\n"); fnotice (file, " -s, --scale Scale the profile counters\n"); + fnotice (file, " -u, --use_imports_file Use the grouping in import files.\n"); fnotice (file, " -n, --normalize Normalize the profile\n"); } @@ -303,7 +495,10 @@ static const struct option rewrite_options[] = { { "verbose", no_argument, NULL, 'v' }, { "output", required_argument, NULL, 'o' }, + { "modu_list", required_argument, NULL, 'l' }, + { "string", required_argument, NULL, 'r' }, { "scale", required_argument, NULL, 's' }, + { "use_imports_file", no_argument, NULL, 'u' }, { "normalize", required_argument, NULL, 'n' }, { 0, 0, 0, 0 } }; @@ -331,8 +526,11 @@ do_rewrite (int argc, char **argv) int numerator = -1; int denominator = -1; + mod_name_id_hash_table = htab_create (500, mod_name_id_htab_hash, + mod_name_id_hash_eq, NULL); + optind = 0; - while ((opt = getopt_long (argc, argv, "vo:s:n:", rewrite_options, NULL)) != -1) + while ((opt = getopt_long (argc, argv, "vo:l:r:s:un:", rewrite_options, NULL)) != -1) { switch (opt) { @@ -343,6 +541,15 @@ do_rewrite (int argc, char **argv) case 'o': output_dir = optarg; break; + case 'l': + lipo_process_modu_list (optarg); + break; + case 'r': + lipo_set_substitute_string (optarg); + break; + case 'u': + set_use_existing_grouping (); + break; case 'n': if (scale != 1.0) { @@ -437,7 +644,7 @@ static void print_version (void) { fnotice (stdout, "%s %s%s\n", progname, pkgversion_string, version_string); - fprintf (stdout, "Copyright %s 2014 Free Software Foundation, Inc.\n", + fnotice (stdout, "Copyright %s 2014 Free Software Foundation, Inc.\n", _("(C)")); fnotice (stdout, _("This is free software; see the source for copying conditions.\n" @@ -496,7 +703,7 @@ process_args (int argc, char **argv) sscanf (optarg, "%d", &ret); if (ret != 0 && ret != 1) { - fprintf (stderr, "LIPO grouping algorithm can only be 0 or 1. \n"); + fnotice (stderr, "LIPO grouping algorithm can only be 0 or 1\n"); exit (-1); } __gcov_lipo_grouping_algorithm = ret; @@ -505,7 +712,7 @@ process_args (int argc, char **argv) sscanf (optarg, "%d", &ret); if (ret < 1) { - fprintf (stderr, "LIPO random group size needs to be positive.\n"); + fnotice (stderr, "LIPO random group size needs to be positive\n"); exit (-1); } __gcov_lipo_random_group_size = ret; @@ -518,7 +725,7 @@ process_args (int argc, char **argv) sscanf (optarg, "%d", &ret); if (ret < 0) { - fprintf (stderr, "LIPO max-memory size needs to be positive. \n"); + fnotice (stderr, "LIPO max-memory size needs to be positive\n"); exit (-1); } __gcov_lipo_max_mem = ret; @@ -527,7 +734,7 @@ process_args (int argc, char **argv) sscanf (optarg, "%d", &ret); if (ret < 0 || ret > 100) { - fprintf (stderr, "LIPO cutoff value range is [0, 100]. \n"); + fnotice (stderr, "LIPO cutoff value range is [0, 100]\n"); exit (-1); } __gcov_lipo_cutoff = ret;; Index: libgcc/dyn-ipa.c =================================================================== --- libgcc/dyn-ipa.c (revision 207435) +++ libgcc/dyn-ipa.c (working copy) @@ -182,6 +182,7 @@ enum GROUPING_ALGORITHM static int flag_alg_mode; static int flag_modu_merge_edges; static int flag_weak_inclusion; +static int flag_use_existing_grouping; static gcov_unsigned_t mem_threshold; /* Returns 0 if no dump is enabled. Returns 1 if text form graph @@ -364,6 +365,7 @@ static void init_dyn_call_graph (void) { unsigned num_modules = 0; + unsigned max_module_id = 0; struct gcov_info *gi_ptr; const char *env_str; int do_dump = (do_cgraph_dump () != 0); @@ -381,12 +383,22 @@ init_dyn_call_graph (void) gi_ptr = gcov_list; for (; gi_ptr; gi_ptr = gi_ptr->next) - num_modules++; + { + unsigned mod_id = get_module_ident (gi_ptr); + num_modules++; + if (max_module_id < mod_id) + max_module_id = mod_id; + } + if (num_modules < max_module_id) + num_modules = max_module_id; + the_dyn_call_graph.num_modules = num_modules; the_dyn_call_graph.modules = XNEWVEC (struct gcov_info *, num_modules); + memset (the_dyn_call_graph.modules, 0, + num_modules * sizeof (struct gcov_info*)); the_dyn_call_graph.sup_modules = XNEWVEC (struct dyn_module_info, num_modules); @@ -476,13 +488,16 @@ void __gcov_finalize_dyn_callgraph (void) { unsigned i; - struct gcov_info *gi_ptr; for (i = 0; i < the_dyn_call_graph.num_modules; i++) { - gi_ptr = the_dyn_call_graph.modules[i]; + struct gcov_info *gi_ptr = the_dyn_call_graph.modules[i]; const struct gcov_fn_info *fi_ptr; unsigned f_ix; + + if (gi_ptr == NULL) + continue; + for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { struct dyn_cgraph_node *node; @@ -651,6 +666,8 @@ gcov_build_callgraph (void) unsigned f_ix, i; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { @@ -901,6 +918,8 @@ gcov_compute_cutoff_count (void) unsigned f_ix; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { @@ -1239,7 +1258,8 @@ gcov_process_cgraph_node (struct dyn_cgraph_node * { struct gcov_info *callee_mod_info = get_module_info (callee_mod_id); - imp_mod_set_insert (imp_modules, callee_mod_info, callee_mod_wt); + if (callee_mod_info) + imp_mod_set_insert (imp_modules, callee_mod_info, callee_mod_wt); } } @@ -1629,6 +1649,8 @@ build_modu_graph (gcov_type cutoff_count) unsigned f_ix; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; modu_nodes[m_ix].module = gi_ptr; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) @@ -1950,6 +1972,8 @@ gcov_compute_module_groups_eager_propagation (gcov unsigned f_ix; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { @@ -1972,6 +1996,8 @@ gcov_compute_module_groups_eager_propagation (gcov unsigned f_ix; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { @@ -2036,7 +2062,8 @@ gcov_compute_random_module_groups (unsigned max_gr if (mod_idx == m_ix) continue; imp_mod_info = get_module_info (mod_idx + 1); - if (!imp_mod_set_insert (imp_modules, imp_mod_info, 1.0)) + if (imp_mod_info && + !imp_mod_set_insert (imp_modules, imp_mod_info, 1.0)) i++; } } @@ -2155,6 +2182,112 @@ gcov_write_module_infos (struct gcov_info *mod_inf } } +/* Set to use module grouping from existing imports files in + the profile directory. */ +void set_use_existing_grouping (void); + +void +set_use_existing_grouping (void) +{ + flag_use_existing_grouping = 1; +} + +#ifdef IN_GCOV_TOOL +extern const char *get_source_profile_dir (void); + +/* find and open the imports files based on da_filename + in GI_PTR. */ + +static FILE * +open_imports_file (struct gcov_info *gi_ptr) +{ + const char *gcda_name; + char *imports_name; + const char *source_dir = ""; + + if (gi_ptr == NULL || gi_ptr->mod_info == NULL) + return NULL; + + gcda_name = gi_ptr->mod_info->da_filename; + gcc_assert (gcda_name); + + source_dir = get_source_profile_dir (); + gcc_assert (source_dir); + imports_name = (char *) alloca (strlen (gcda_name) + strlen (source_dir) + + strlen (".gcda.imports") + 2); + strcpy (imports_name, source_dir); + strcat (imports_name, "/"); + strcat (imports_name, gcda_name); + strcat (imports_name, ".gcda.imports"); + return fopen (imports_name, "r"); +} + +extern int get_module_id_from_name (const char *); + +#endif /* IN_GCOV_TOOL */ + +/* Use the module grouping from existing imports files in + the profile directory. */ + +static void +read_modu_groups_from_imports_files (void) +{ +#ifdef IN_GCOV_TOOL + unsigned m_ix; + + init_dyn_call_graph (); + + for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) + { + struct gcov_info *gi_ptr = the_dyn_call_graph.modules[m_ix]; + FILE *fd; + struct dyn_pointer_set *imp_modules; + + if (gi_ptr == NULL) + continue; + + imp_modules = gcov_get_module_imp_module_set + (&the_dyn_call_graph.sup_modules[m_ix]); + + if ((fd = open_imports_file (gi_ptr)) != NULL) + { + char *line = NULL; + size_t linecap = 0; + while (getline (&line, &linecap, fd) != -1) + { + unsigned mod_id = 0; + char *name = strtok (line, " \t\n"); + + if (name && (mod_id = get_module_id_from_name (name))) + { + struct gcov_info *imp_mod_info; + unsigned mod_idx = mod_id - 1; + if (mod_idx == m_ix) + continue; + imp_mod_info = get_module_info (mod_idx + 1); + imp_mod_set_insert (imp_modules, imp_mod_info, 1.0); + } + free (line); + line = NULL; + } + fclose (fd); + } + } + + /* Now compute the export attribute */ + for (m_ix = 0; m_ix < the_dyn_call_graph.num_modules; m_ix++) + { + struct dyn_module_info *mi + = &the_dyn_call_graph.sup_modules[m_ix]; + if (mi->imported_modules) + pointer_set_traverse (mi->imported_modules, + gcov_mark_export_modules, 0, 0, 0); + } +#else /* !IN_GCOV_TOOL */ + gcc_assert (0); +#endif /* IN_GCOV_TOOL */ +} + /* Compute module groups needed for L-IPO compilation. */ void @@ -2192,6 +2325,12 @@ __gcov_compute_module_groups (void) return; } + if (flag_use_existing_grouping) + { + read_modu_groups_from_imports_files (); + return; + } + /* First compute dynamic call graph. */ gcov_build_callgraph (); @@ -2333,6 +2472,8 @@ gcov_dump_callgraph (gcov_type cutoff_count) unsigned f_ix; gi_ptr = the_dyn_call_graph.modules[m_ix]; + if (gi_ptr == NULL) + continue; for (f_ix = 0; f_ix < gi_ptr->n_functions; f_ix++) { Index: libgcc/libgcov-util.c =================================================================== --- libgcc/libgcov-util.c (revision 207435) +++ libgcc/libgcov-util.c (working copy) @@ -267,6 +267,114 @@ read_gcda_finalize (struct gcov_info *obj_info) extern void gcov_read_module_info (struct gcov_module_info *mod_info, gcov_unsigned_t len); +/* Substitute string is of this format: + old_sub1:new_sub1[,old_sub2:new_sub2] + Note that we only apply the substutution ONE time, for the first match. */ + +static const char *substitute_string; + +/* A global function to set the substitute string. */ + +void +lipo_set_substitute_string (const char *str) +{ + char *sub_dup = xstrdup (str); + char *cur_sub = sub_dup; + + /* First check if the str is in the right form. + Dup the string and split it into tokens with + ',' and ':' as the delimiters. */ + do + { + char *new_str; + char *next = strchr (cur_sub, ','); + if (next) + *next++ = '\0'; + new_str = strchr (cur_sub, ':'); + if (!new_str) + { + fprintf (stderr, "Warning: Skip invalid substibution string:%s\n", + str); + free (sub_dup); + return; + } + *new_str++ = '\0'; + cur_sub = next; + } while (cur_sub); + + free (sub_dup); + substitute_string = str; +} + +/* Replace the first occurance of CUT_STR to NEW_STR in INPUT_STR. */ + +static char * +lipo_process_substitute_string_1 (char *input_str, + const char *cur_str, + const char *new_str) +{ + char *p; + + if (!input_str || !cur_str || !new_str) + return input_str; + + if ((p = strstr (input_str, cur_str)) != NULL) + { + char *t; + + if (verbose) + printf ("Substitute: %s \n", input_str); + t = (char*) xmalloc (strlen (input_str) + 1 + + strlen (new_str) - strlen (cur_str)); + *p = 0; + + strcpy (t, input_str); + strcat (t, new_str); + strcat (t, p + strlen (cur_str)); + if (verbose) + printf (" --> %s\n", t); + return t; + } + + return input_str; +} + +/* Parse the substitute string and apply to the INPUT_STR. */ + +static char * +lipo_process_substitute_string (char *input_str) +{ + char *sub_dup, *cur_sub, *ret; + + if (substitute_string == NULL) + return input_str; + + sub_dup = xstrdup (substitute_string); + cur_sub = sub_dup; + ret = input_str; + + /* Dup the string and split it into tokens with + ',' and ':' as the delimiters. */ + do + { + char *new_str, *new_input; + char *next = strchr (cur_sub, ','); + if (next) + *next++ = '\0'; + new_str = strchr (cur_sub, ':'); + gcc_assert (new_str); + *new_str++ = '\0'; + new_input = ret; + ret = lipo_process_substitute_string_1 (new_input, cur_sub, new_str); + if (ret != new_input) + free (new_input); + cur_sub = next; + } while (cur_sub); + + free (sub_dup); + return ret; +} + /* This function reads module_info from a gcda file. */ static void @@ -280,7 +388,11 @@ tag_module_info (unsigned tag ATTRIBUTE_UNUSED, un gcov_read_module_info (mod_info, length); if (mod_info->is_primary) - curr_module_info = mod_info; + { + mod_info->da_filename = + lipo_process_substitute_string (mod_info->da_filename); + curr_module_info = mod_info; + } else free (mod_info); } @@ -295,7 +407,8 @@ read_gcda_file (const char *filename) unsigned depth = 0; unsigned magic, version; struct gcov_info *obj_info; - int i; + int i, len; + char *str_dup; for (i=0; i< GCOV_COUNTERS; i++) k_ctrs_mask[i] = 0; @@ -335,15 +448,11 @@ read_gcda_file (const char *filename) curr_fn_info = 0; curr_module_info = 0; - { - char *str_dup = (char*) xmalloc (strlen (filename) + 1); - int len; + str_dup = lipo_process_substitute_string (xstrdup (filename)); + obj_info->filename = str_dup; - strcpy (str_dup, filename); - obj_info->filename = str_dup; - if ((len = strlen (filename)) > max_filename_len) - max_filename_len = len; - } + if ((len = strlen (str_dup)) > max_filename_len) + max_filename_len = len; /* Read stamp. */ obj_info->stamp = gcov_read_unsigned (); @@ -420,6 +529,21 @@ read_gcda_file (const char *filename) return obj_info; } +extern int is_module_available (const char *, unsigned *, int); + +/* If only use the modules in the modu_list. */ + +static int flag_use_modu_list; + +/* Set to use only the modules in the modu_list file. */ + +void +set_use_modu_list (void) +{ + flag_use_modu_list = 1; +} + + /* This will be called by ftw(). It opens and read a gcda file FILENAME. Return a non-zero value to stop the tree walk. */ @@ -450,12 +574,39 @@ ftw_read_file (const char *filename, obj_info = read_gcda_file (filename); + if (obj_info->mod_info) + { + unsigned mod_id = obj_info->mod_info->ident; + int create = (flag_use_modu_list ? 0 : 1); + + if (!is_module_available (obj_info->mod_info->source_filename, + &mod_id, create)) + { + if (verbose) + fprintf (stderr, "warning: module %s (%d) is not avail\n", + obj_info->mod_info->source_filename, mod_id); + return 0; + } + } + obj_info->next = gcov_info_head; gcov_info_head = obj_info; return 0; } +/* Source profile directory name. */ + +static const char *source_profile_dir; + +/* Return Source profile directory name. */ + +const char * +get_source_profile_dir (void) +{ + return source_profile_dir; +} + /* Initializer for reading a profile dir. */ static inline void @@ -490,6 +641,8 @@ gcov_read_profile_dir (const char* dir_name, int r fprintf (stderr, "%s is not a directory\n", dir_name); return NULL; } + source_profile_dir = getcwd (NULL, 0); + ftw (".", ftw_read_file, 50); ret = chdir (pwd); free (pwd);