From patchwork Tue Oct 7 20:44:23 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rong Xu X-Patchwork-Id: 397454 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 737A71400B6 for ; Wed, 8 Oct 2014 07:44:38 +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:date:message-id:subject:from:to:content-type; q= dns; s=default; b=kf0KvweywXa6Di77vJ/Aj4XYVvFqtGr0XyA+INWOBjR/8P w4IdZ1myT1Qx6e40os05qYqFRyk9tqOYMufNP+asa+hzD7QX7T4sqIO8Fkt6eJdk LcwdywJxm3zFeDKjQeqivxWFE9TQZevKOsoYNoBemypTNY3Ty7NonVz25m4fY= 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:date:message-id:subject:from:to:content-type; s= default; bh=3p6+asW5/7lBwDI4d/k6V+/CRZA=; b=u5t32CQMM6AY4FX3Ui6Y r2047ZISbrtYXy6Eixz0GLODoGNpJQJev/V16WLl6nUxj9JeW8RYP6SvIOjPnYGx 4A7lgG2lMUlLNtYAKNwmxSMQw+gpDsQhQW0bCnI5R80odc9RDTCY2l2tgriCiNf9 +veItFxqOKcAbXmogdU4l7c= Received: (qmail 26303 invoked by alias); 7 Oct 2014 20:44:29 -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 26290 invoked by uid 89); 7 Oct 2014 20:44:29 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW, SPF_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 X-HELO: mail-ob0-f169.google.com Received: from mail-ob0-f169.google.com (HELO mail-ob0-f169.google.com) (209.85.214.169) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Tue, 07 Oct 2014 20:44:25 +0000 Received: by mail-ob0-f169.google.com with SMTP id m8so6394722obr.0 for ; Tue, 07 Oct 2014 13:44:23 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:date:message-id:subject:from:to :content-type; bh=DMU8TRpruiv6GvcPYtYn04XGAsRMHuy1Eayaa95DFcQ=; b=m+MnaXrlL5Za/2/lVcsSdCpTvTa1n+UH+vZNydIkBPye9XlwE0egCPb9dSP/x4rS0/ l95XcgkwyRDW+Bq3QYgMr8ib6LWKrAJRYuW9tJm22YghcZun+BnV6feVxY3RhPq//FFQ zbqRD/VaTBDwClGec5STOjpIoMEu+oxdfRItc20BvYNa31gEBg5IF4rXhRzeVnL6iAcm LJ1HdD1DEnCKlyBhCbZKYFjiCSY92zE1+m0m/D/+Gnga1Hm2SQZbh5Tkt1pJLoL0C0OP yhcyZt+MuG8/zzmyQsp3kYMON/+7ezty2dev0Lj24NYo3zSG3eb6lQDM40hpm7LLK5O7 oFvg== X-Gm-Message-State: ALoCoQmnIKoN7V3fUAd05ZW3FfAP28S2VTszShmbXws0d5PHOAvTEyBbvMZgbYBfYoNwcxhsfR4a MIME-Version: 1.0 X-Received: by 10.182.80.66 with SMTP id p2mr6293089obx.77.1412714663706; Tue, 07 Oct 2014 13:44:23 -0700 (PDT) Received: by 10.182.109.100 with HTTP; Tue, 7 Oct 2014 13:44:23 -0700 (PDT) Date: Tue, 7 Oct 2014 13:44:23 -0700 Message-ID: Subject: [PATCH] add overlap function to gcov-tool From: Rong Xu To: GCC Patches , Jan Hubicka X-IsSubscribed: yes Hi, This patch adds overlap functionality to gcov-tool. The overlap score estimates the similarity of two profiles. Currently it only computes overlap for arc counters. The overlap score is defined as \sum minimum (p1-counter[i] / p1-sum-all, p2-counter[i] / p2-sum-all) where p1-counter[i] and p2-counter[2] are two matched counter from profile1 and profiler2. p1-sum-all and p2-sum-all are the sum-all counters in profiler1 and profile2, repetitively. The resulting score is a value ranging from 0.0 to 1.0 where 0.0 means no match and 1.0 mean a perfect match. This tool can be used in performance triaging and reducing the fdo training set size (where similar inputs can be pruned). Tested with spec2006 profiles. Thanks, -Rong 2014-10-07 Rong Xu * gcc/gcov-tool.c (profile_overlap): New driver function to compute profile overlap. (print_overlap_usage_message): New. (overlap_usage): New. (do_overlap): New. (print_usage): Add calls to overlap function. (main): Ditto. * libgcc/libgcov-util.c (read_gcda_file): Fix format. (find_match_gcov_info): Ditto. (calculate_2_entries): New. (compute_one_gcov): Ditto. (gcov_info_count_all_cold): Ditto. (gcov_info_count_all_zero): Ditto. (extract_file_basename): Ditto. (get_file_basename): Ditto. (set_flag): Ditto. (matched_gcov_info): Ditto. (calculate_overlap): Ditto. (gcov_profile_overlap): Ditto. * libgcc/libgcov-driver.c (compute_summary): Make it avavilable for external calls. * gcc/doc/gcov-tool.texi: Add documentation. Index: gcc/gcov-tool.c =================================================================== --- gcc/gcov-tool.c (revision 215981) +++ gcc/gcov-tool.c (working copy) @@ -39,6 +39,7 @@ see the files COPYING3 and COPYING.RUNTIME respect #include extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, 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); extern struct gcov_info* gcov_read_profile_dir (const char*, int); @@ -368,6 +369,121 @@ do_rewrite (int argc, char **argv) return ret; } +/* Driver function to computer the overlap score b/w profile D1 and D2. + Return 1 on error and 0 if OK. */ + +static int +profile_overlap (const char *d1, const char *d2) +{ + struct gcov_info *d1_profile; + struct gcov_info *d2_profile; + + d1_profile = gcov_read_profile_dir (d1, 0); + if (!d1_profile) + return 1; + + if (d2) + { + d2_profile = gcov_read_profile_dir (d2, 0); + if (!d2_profile) + return 1; + + return gcov_profile_overlap (d1_profile, d2_profile); + } + + return 1; +} + +/* Usage message for profile overlap. */ + +static void +print_overlap_usage_message (int error_p) +{ + FILE *file = error_p ? stderr : stdout; + + fnotice (file, " overlap [options] Compute the overlap of two profiles\n"); + fnotice (file, " -v, --verbose Verbose mode\n"); + fnotice (file, " -h, --hotonly Only print info for hot objects/functions\n"); + fnotice (file, " -f, --function Print function level info\n"); + fnotice (file, " -F, --fullname Print full filename\n"); + fnotice (file, " -o, --object Print object level info\n"); + fnotice (file, " -t , --hot_threshold Set the threshold for hotness\n"); + +} + +static const struct option overlap_options[] = +{ + { "verbose", no_argument, NULL, 'v' }, + { "function", no_argument, NULL, 'f' }, + { "fullname", no_argument, NULL, 'F' }, + { "object", no_argument, NULL, 'o' }, + { "hotonly", no_argument, NULL, 'h' }, + { "hot_threshold", required_argument, NULL, 't' }, + { 0, 0, 0, 0 } +}; + +/* Print overlap usage and exit. */ + +static void +overlap_usage (void) +{ + fnotice (stderr, "Overlap subcomand usage:"); + print_overlap_usage_message (true); + exit (FATAL_EXIT_CODE); +} + +int overlap_func_level; +int overlap_obj_level; +int overlap_hot_only; +int overlap_use_fullname; +double overlap_hot_threshold = 0.005; + +/* Driver for profile overlap sub-command. */ + +static int +do_overlap (int argc, char **argv) +{ + int opt; + int ret; + + optind = 0; + while ((opt = getopt_long (argc, argv, "vfFoht:", overlap_options, NULL)) != -1) + { + switch (opt) + { + case 'v': + verbose = true; + gcov_set_verbose (); + break; + case 'f': + overlap_func_level = 1; + break; + case 'F': + overlap_use_fullname = 1; + break; + case 'o': + overlap_obj_level = 1; + break; + case 'h': + overlap_hot_only = 1; + break; + case 't': + overlap_hot_threshold = atof (optarg); + break; + default: + overlap_usage (); + } + } + + if (argc - optind == 2) + ret = profile_overlap (argv[optind], argv[optind+1]); + else + overlap_usage (); + + return ret; +} + + /* Print a usage message and exit. If ERROR_P is nonzero, this is an error, otherwise the output of --help. */ @@ -383,6 +499,7 @@ print_usage (int error_p) fnotice (file, " -v, --version Print version number, then exit\n"); print_merge_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", bug_report_url); exit (status); @@ -471,6 +588,8 @@ main (int argc, char **argv) return do_merge (argc - optind, argv + optind); else if (!strcmp (sub_command, "rewrite")) return do_rewrite (argc - optind, argv + optind); + else if (!strcmp (sub_command, "overlap")) + return do_overlap (argc - optind, argv + optind); print_usage (true); } Index: libgcc/libgcov-util.c =================================================================== --- libgcc/libgcov-util.c (revision 215981) +++ libgcc/libgcov-util.c (working copy) @@ -319,59 +319,59 @@ read_gcda_file (const char *filename) tag = gcov_read_unsigned (); if (!tag) - break; + break; length = gcov_read_unsigned (); base = gcov_position (); mask = GCOV_TAG_MASK (tag) >> 1; for (tag_depth = 4; mask; mask >>= 8) - { - if (((mask & 0xff) != 0xff)) - { - warning (0, "%s:tag `%x' is invalid\n", filename, tag); - break; - } - tag_depth--; - } + { + if (((mask & 0xff) != 0xff)) + { + warning (0, "%s:tag `%x' is invalid\n", filename, tag); + break; + } + tag_depth--; + } for (format = tag_table; format->name; format++) - if (format->tag == tag) - goto found; + if (format->tag == tag) + goto found; format = &tag_table[GCOV_TAG_IS_COUNTER (tag) ? 2 : 1]; found:; if (tag) - { - if (depth && depth < tag_depth) - { - if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag)) - warning (0, "%s:tag `%x' is incorrectly nested\n", - filename, tag); - } - depth = tag_depth; - tags[depth - 1] = tag; - } + { + if (depth && depth < tag_depth) + { + if (!GCOV_TAG_IS_SUBTAG (tags[depth - 1], tag)) + warning (0, "%s:tag `%x' is incorrectly nested\n", + filename, tag); + } + depth = tag_depth; + tags[depth - 1] = tag; + } if (format->proc) { - unsigned long actual_length; + unsigned long actual_length; - (*format->proc) (tag, length); + (*format->proc) (tag, length); - actual_length = gcov_position () - base; - if (actual_length > length) - warning (0, "%s:record size mismatch %lu bytes overread\n", - filename, actual_length - length); - else if (length > actual_length) - warning (0, "%s:record size mismatch %lu bytes unread\n", - filename, length - actual_length); - } + actual_length = gcov_position () - base; + if (actual_length > length) + warning (0, "%s:record size mismatch %lu bytes overread\n", + filename, actual_length - length); + else if (length > actual_length) + warning (0, "%s:record size mismatch %lu bytes unread\n", + filename, length - actual_length); + } gcov_sync (base, length); if ((error = gcov_is_error ())) - { - warning (0, error < 0 ? "%s:counter overflow at %lu\n" : - "%s:read error at %lu\n", filename, - (long unsigned) gcov_position ()); - break; - } + { + warning (0, error < 0 ? "%s:counter overflow at %lu\n" : + "%s:read error at %lu\n", filename, + (long unsigned) gcov_position ()); + break; + } } read_gcda_finalize (obj_info); @@ -577,7 +577,8 @@ gcov_merge (struct gcov_info *info1, struct gcov_i Return NULL if there is no match. */ static struct gcov_info * -find_match_gcov_info (struct gcov_info **array, int size, struct gcov_info *info) +find_match_gcov_info (struct gcov_info **array, int size, + struct gcov_info *info) { struct gcov_info *gi_ptr; struct gcov_info *ret = NULL; @@ -872,7 +873,530 @@ gcov_profile_normalize (struct gcov_info *profile, scale_factor = (float)max_val / curr_max_val; if (verbose) - fnotice (stdout, "max_val is %lld\n", (long long) curr_max_val); + fnotice (stdout, "max_val is %"PRId64"\n", curr_max_val); return gcov_profile_scale (profile, scale_factor, 0, 0); } + +/* The following variables are defined in gcc/gcov-tool.c. */ +extern int overlap_func_level; +extern int overlap_obj_level; +extern int overlap_hot_only; +extern int overlap_use_fullname; +extern double overlap_hot_threshold; + +/* Compute the overlap score of two values. The score is defined as: + min (V1/SUM_1, V2/SUM_2) */ + +static double +calculate_2_entries (const unsigned long v1, const unsigned long v2, + const double sum_1, const double sum_2) +{ + double val1 = (sum_1 == 0.0 ? 0.0 : v1/sum_1); + double val2 = (sum_2 == 0.0 ? 0.0 : v2/sum_2); + + if (val2 < val1) + val1 = val2; + + return val1; +} + +/* Compute the overlap score between GCOV_INFO1 and GCOV_INFO2. + SUM_1 is the sum_all for profile1 where GCOV_INFO1 belongs. + SUM_2 is the sum_all for profile2 where GCOV_INFO2 belongs. + This function also updates cumulative score CUM_1_RESULT and + CUM_2_RESULT. */ + +static double +compute_one_gcov (const struct gcov_info *gcov_info1, + const struct gcov_info *gcov_info2, + const double sum_1, const double sum_2, + double *cum_1_result, double *cum_2_result) +{ + unsigned f_ix; + double ret = 0; + double cum_1 = 0, cum_2 = 0; + const struct gcov_info *gcov_info = 0; + double *cum_p; + double sum; + + gcc_assert (gcov_info1 || gcov_info2); + if (!gcov_info1) + { + gcov_info = gcov_info2; + cum_p = cum_2_result; + sum = sum_2; + *cum_1_result = 0; + } else + if (!gcov_info2) + { + gcov_info = gcov_info1; + cum_p = cum_1_result; + sum = sum_1; + *cum_2_result = 0; + } + + if (gcov_info) + { + for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++) + { + unsigned t_ix; + const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix]; + if (!gfi_ptr || gfi_ptr->key != gcov_info) + continue; + const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs; + for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) + { + unsigned c_num; + + if (!gcov_info->merge[t_ix]) + continue; + + for (c_num = 0; c_num < ci_ptr->num; c_num++) + { + cum_1 += ci_ptr->values[c_num] / sum; + } + ci_ptr++; + } + } + *cum_p = cum_1; + return 0.0; + } + + for (f_ix = 0; f_ix < gcov_info1->n_functions; f_ix++) + { + unsigned t_ix; + double func_cum_1 = 0.0; + double func_cum_2 = 0.0; + double func_val = 0.0; + int nonzero = 0; + int hot = 0; + const struct gcov_fn_info *gfi_ptr1 = gcov_info1->functions[f_ix]; + const struct gcov_fn_info *gfi_ptr2 = gcov_info2->functions[f_ix]; + + if (!gfi_ptr1 || gfi_ptr1->key != gcov_info1) + continue; + if (!gfi_ptr2 || gfi_ptr2->key != gcov_info2) + continue; + + const struct gcov_ctr_info *ci_ptr1 = gfi_ptr1->ctrs; + const struct gcov_ctr_info *ci_ptr2 = gfi_ptr2->ctrs; + for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) + { + unsigned c_num; + + if (!gcov_info1->merge[t_ix]) + continue; + + for (c_num = 0; c_num < ci_ptr1->num; c_num++) + { + if (ci_ptr1->values[c_num] | ci_ptr2->values[c_num]) + { + func_val += calculate_2_entries (ci_ptr1->values[c_num], + ci_ptr2->values[c_num], + sum_1, sum_2); + + func_cum_1 += ci_ptr1->values[c_num] / sum_1; + func_cum_2 += ci_ptr2->values[c_num] / sum_2; + nonzero = 1; + if (ci_ptr1->values[c_num] / sum_1 >= overlap_hot_threshold || + ci_ptr2->values[c_num] / sum_2 >= overlap_hot_threshold) + hot = 1; + } + } + ci_ptr1++; + ci_ptr2++; + } + ret += func_val; + cum_1 += func_cum_1; + cum_2 += func_cum_2; + if (overlap_func_level && nonzero && (!overlap_hot_only || hot)) + { + printf(" \tfunc_id=%10d \toverlap =%6.5f%% (%5.5f%% %5.5f%%)\n", + gfi_ptr1->ident, func_val*100, func_cum_1*100, func_cum_2*100); + } + } + *cum_1_result = cum_1; + *cum_2_result = cum_2; + return ret; +} + +/* Test if all counter values in this GCOV_INFO are cold. + "Cold" is defined as the counter value being less than + or equal to THRESHOLD. */ + +static bool +gcov_info_count_all_cold (const struct gcov_info *gcov_info, + gcov_type threshold) +{ + unsigned f_ix; + + for (f_ix = 0; f_ix < gcov_info->n_functions; f_ix++) + { + unsigned t_ix; + const struct gcov_fn_info *gfi_ptr = gcov_info->functions[f_ix]; + + if (!gfi_ptr || gfi_ptr->key != gcov_info) + continue; + const struct gcov_ctr_info *ci_ptr = gfi_ptr->ctrs; + for (t_ix = 0; t_ix < GCOV_COUNTERS_SUMMABLE; t_ix++) + { + unsigned c_num; + + if (!gcov_info->merge[t_ix]) + continue; + + for (c_num = 0; c_num < ci_ptr->num; c_num++) + { + if (ci_ptr->values[c_num] > threshold) + return false; + } + ci_ptr++; + } + } + + return true; +} + +/* Test if all counter values in this GCOV_INFO are 0. */ + +static bool +gcov_info_count_all_zero (const struct gcov_info *gcov_info) +{ + return gcov_info_count_all_cold (gcov_info, 0); +} + +/* A pair of matched GCOV_INFO. + The flag is a bitvector: + b0: obj1's all counts are 0; + b1: obj1's all counts are cold (but no 0); + b2: obj1 is hot; + b3: no obj1 to match obj2; + b4: obj2's all counts are 0; + b5: obj2's all counts are cold (but no 0); + b6: obj2 is hot; + b7: no obj2 to match obj1; + */ +struct overlap_t { + const struct gcov_info *obj1; + const struct gcov_info *obj2; + char flag; +}; + +#define FLAG_BOTH_ZERO(flag) ((flag & 0x1) && (flag & 0x10)) +#define FLAG_BOTH_COLD(flag) ((flag & 0x2) && (flag & 0x20)) +#define FLAG_ONE_HOT(flag) ((flag & 0x4) || (flag & 0x40)) + +/* Cumlative overlap dscore for profile1 and profile2. */ +static double overlap_sum_1, overlap_sum_2; + +/* sum_all for profile1 and profile2. */ +static gcov_type p1_sum_all, p2_sum_all; + +/* run_max for profile1 and profile2. */ +static gcov_type p1_run_max, p2_run_max; + +/* The number of gcda files in the profiles. */ +static unsigned gcda_files[2]; + +/* The number of unique gcda files in the profiles + (not existing in the other profile). */ +static unsigned unique_gcda_files[2]; + +/* The number of gcda files that all counter values are 0. */ +static unsigned zero_gcda_files[2]; + +/* The number of gcda files that all counter values are cold (but not 0). */ +static unsigned cold_gcda_files[2]; + +/* The number of gcda files that includes hot counter values. */ +static unsigned hot_gcda_files[2]; + +/* The number of gcda files with hot count value in either profiles. */ +static unsigned both_hot_cnt; + +/* The number of gcda files with all counts cold (but not 0) in + both profiles. */ +static unsigned both_cold_cnt; + +/* The number of gcda files with all counts 0 in both profiles. */ +static unsigned both_zero_cnt; + +/* Extract the basename of the filename NAME. */ + +static char * +extract_file_basename (const char *name) +{ + char *str; + int len = 0; + char *path = xstrdup (name); + char sep_str[2]; + + sep_str[0] = DIR_SEPARATOR; + sep_str[1] = 0; + str = strstr(path, sep_str); + do{ + len = strlen(str) + 1; + path = &path[strlen(path) - len + 2]; + str = strstr(path, sep_str); + } while(str); + + return path; +} + +/* Utility function to get the filename. */ + +static const char * +get_file_basename (const char *name) +{ + if (overlap_use_fullname) + return name; + return extract_file_basename (name); +} + +/* A utility function to set the flag for the gcda files. */ + +static void +set_flag (struct overlap_t *e) +{ + char flag = 0; + + if (!e->obj1) + { + unique_gcda_files[1]++; + flag = 0x8; + } + else + { + gcda_files[0]++; + if (gcov_info_count_all_zero (e->obj1)) + { + zero_gcda_files[0]++; + flag = 0x1; + } + else + if (gcov_info_count_all_cold (e->obj1, overlap_sum_1 + * overlap_hot_threshold)) + { + cold_gcda_files[0]++; + flag = 0x2; + } + else + { + hot_gcda_files[0]++; + flag = 0x4; + } + } + + if (!e->obj2) + { + unique_gcda_files[0]++; + flag |= (0x8 << 4); + } + else + { + gcda_files[1]++; + if (gcov_info_count_all_zero (e->obj2)) + { + zero_gcda_files[1]++; + flag |= (0x1 << 4); + } + else + if (gcov_info_count_all_cold (e->obj2, overlap_sum_2 + * overlap_hot_threshold)) + { + cold_gcda_files[1]++; + flag |= (0x2 << 4); + } + else + { + hot_gcda_files[1]++; + flag |= (0x4 << 4); + } + } + + gcc_assert (flag); + e->flag = flag; +} + +/* Test if INFO1 and INFO2 are from the matched source file. + Return 1 if they match; return 0 otherwise. */ + +static int +matched_gcov_info (const struct gcov_info *info1, const struct gcov_info *info2) +{ + /* For FDO, we have to match the name. This can be expensive. + Maybe we should use hash here. */ + if (strcmp (info1->filename, info2->filename)) + return 0; + + if (info1->n_functions != info2->n_functions) + { + fnotice (stderr, "mismatched profiles in %s (%d functions" + " vs %d functions)\n", + info1->filename, + info1->n_functions, + info2->n_functions); + return 0; + } + return 1; +} + +/* Defined in libgcov-driver.c. */ +extern gcov_unsigned_t compute_summary (struct gcov_info *, + struct gcov_summary *, size_t *); + +/* Compute the overlap score of two profiles with the head of GCOV_LIST1 and + GCOV_LIST1. Return a number ranging from [0.0, 1.0], with 0.0 meaning no + match and 1.0 meaning a perfect match. */ + +static double +calculate_overlap (struct gcov_info *gcov_list1, + struct gcov_info *gcov_list2) +{ + struct gcov_summary this_prg; + unsigned list1_cnt = 0, list2_cnt= 0, all_cnt; + unsigned int i, j; + size_t max_length; + const struct gcov_info *gi_ptr; + struct overlap_t *all_infos; + + compute_summary (gcov_list1, &this_prg, &max_length); + overlap_sum_1 = (double) (this_prg.ctrs[0].sum_all); + p1_sum_all = this_prg.ctrs[0].sum_all; + p1_run_max = this_prg.ctrs[0].run_max; + compute_summary (gcov_list2, &this_prg, &max_length); + overlap_sum_2 = (double) (this_prg.ctrs[0].sum_all); + p2_sum_all = this_prg.ctrs[0].sum_all; + p2_run_max = this_prg.ctrs[0].run_max; + + for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next) + list1_cnt++; + for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next) + list2_cnt++; + all_cnt = list1_cnt + list2_cnt; + all_infos = (struct overlap_t *) xmalloc (sizeof (struct overlap_t) + * all_cnt * 2); + gcc_assert (all_infos); + + i = 0; + for (gi_ptr = gcov_list1; gi_ptr; gi_ptr = gi_ptr->next, i++) + { + all_infos[i].obj1 = gi_ptr; + all_infos[i].obj2 = 0; + } + + for (gi_ptr = gcov_list2; gi_ptr; gi_ptr = gi_ptr->next, i++) + { + all_infos[i].obj1 = 0; + all_infos[i].obj2 = gi_ptr; + } + + for (i = list1_cnt; i < all_cnt; i++) + { + if (all_infos[i].obj2 == 0) + continue; + for (j = 0; j < list1_cnt; j++) + { + if (all_infos[j].obj2 != 0) + continue; + if (matched_gcov_info (all_infos[i].obj2, all_infos[j].obj1)) + { + all_infos[j].obj2 = all_infos[i].obj2; + all_infos[i].obj2 = 0; + break; + } + } + } + + for (i = 0; i < all_cnt; i++) + if (all_infos[i].obj1 || all_infos[i].obj2) + { + set_flag (all_infos + i); + if (FLAG_ONE_HOT (all_infos[i].flag)) + both_hot_cnt++; + if (FLAG_BOTH_COLD(all_infos[i].flag)) + both_cold_cnt++; + if (FLAG_BOTH_ZERO(all_infos[i].flag)) + both_zero_cnt++; + } + + double prg_val = 0; + double sum_val = 0; + double sum_cum_1 = 0; + double sum_cum_2 = 0; + + for (i = 0; i < all_cnt; i++) + { + double val; + double cum_1, cum_2; + const char *filename; + + if (all_infos[i].obj1 == 0 && all_infos[i].obj2 == 0) + continue; + if (FLAG_BOTH_ZERO (all_infos[i].flag)) + continue; + + if (all_infos[i].obj1) + filename = get_file_basename (all_infos[i].obj1->filename); + else + filename = get_file_basename (all_infos[i].obj2->filename); + + if (overlap_func_level) + printf("\n processing %36s:\n", filename); + + val = compute_one_gcov (all_infos[i].obj1, all_infos[i].obj2, + overlap_sum_1, overlap_sum_2, &cum_1, &cum_2); + + if (overlap_obj_level && (!overlap_hot_only || FLAG_ONE_HOT (all_infos[i].flag))) + { + printf(" obj=%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n", + filename, val*100, cum_1*100, cum_2*100); + sum_val += val; + sum_cum_1 += cum_1; + sum_cum_2 += cum_2; + } + + prg_val += val; + + } + + if (overlap_obj_level) + printf(" SUM:%36s overlap = %6.2f%% (%5.2f%% %5.2f%%)\n", + "", sum_val*100, sum_cum_1*100, sum_cum_2*100); + + printf (" Statistics:\n" + " profile1_# profile2_# overlap_#\n"); + printf (" gcda files: %12u\t%12u\t%12u\n", gcda_files[0], gcda_files[1], + gcda_files[0]-unique_gcda_files[0]); + printf (" unique files: %12u\t%12u\n", unique_gcda_files[0], + unique_gcda_files[1]); + printf (" hot files: %12u\t%12u\t%12u\n", hot_gcda_files[0], + hot_gcda_files[1], both_hot_cnt); + printf (" cold files: %12u\t%12u\t%12u\n", cold_gcda_files[0], + cold_gcda_files[1], both_cold_cnt); + printf (" zero files: %12u\t%12u\t%12u\n", zero_gcda_files[0], + zero_gcda_files[1], both_zero_cnt); + printf (" sum_all: %12"PRId64"\t%12"PRId64"\n", p1_sum_all, p2_sum_all); + printf (" run_max: %12"PRId64"\t%12"PRId64"\n", p1_run_max, p2_run_max); + + return prg_val; +} + +/* Computer the overlap score of two lists of gcov_info objects PROFILE1 and PROFILE2. + Return 0 on success: without mismatch. Reutrn 1 on error. */ + +int +gcov_profile_overlap (struct gcov_info *profile1, struct gcov_info *profile2) +{ + double result; + + result = calculate_overlap (profile1, profile2); + + if (result > 0) + { + printf("\nProgram level overlap result is %3.2f%%\n\n", result*100); + return 0; + } + return 1; +} Index: libgcc/libgcov-driver.c =================================================================== --- libgcc/libgcov-driver.c (revision 215981) +++ libgcc/libgcov-driver.c (working copy) @@ -274,7 +274,10 @@ static struct gcov_summary_buffer *sum_buffer; It computes and returns CRC32 and stored summary in THIS_PRG. Also determines the longest filename length of the info files. */ -static gcov_unsigned_t +#if !IN_GCOV_TOOL +static +#endif +gcov_unsigned_t compute_summary (struct gcov_info *list, struct gcov_summary *this_prg, size_t *max_length) { Index: gcc/doc/gcov-tool.texi =================================================================== --- gcc/doc/gcov-tool.texi (revision 215981) +++ gcc/doc/gcov-tool.texi (working copy) @@ -103,8 +103,7 @@ in these kind of counters. @section Invoking @command{gcov-tool} @smallexample -gcov-tool @r{[}@var{global-options}@r{]} SUB_COMMAND -@r{[}@var{sub_command-options}@r{]} @var{profile_dir} +gcov-tool @r{[}@var{global-options}@r{]} SUB_COMMAND @r{[}@var{sub_command-options}@r{]} @var{profile_dir} @end smallexample @command{gcov-tool} accepts the following options: @@ -123,6 +122,15 @@ gcov-tool rewrite [rewrite-options] @var{directory [@option{-o}|@option{--output} @var{directory}] [@option{-s}|@option{--scale} @var{float_or_simple-frac_value}] [@option{-n}|@option{--normalize} @var{long_long_value}] + +gcov-tool overlap [overlap-options] @var{directory1} @var{directory2} + [@option{-v}|@option{--verbose}] + [@option{-h}|@option{--hotonly}] + [@option{-f}|@option{--function}] + [@option{-F}|@option{--fullname}] + [@option{-o}|@option{--object}] + [@option{-t}|@option{--hot_threshold}] @var{float} + @c man end @c man begin SEEALSO gpl(7), gfdl(7), fsf-funding(7), gcc(1), gcov(1) and the Info entry for @@ -182,8 +190,42 @@ or simple fraction value form, such 1, 2, 2/3, and @itemx --normalize Normalize the profile. The specified value is the max counter value in the new profile. +@end table +@item overlap +Computer the overlap score between the two specified profile directories. +The overlap score is computed based on the arc profiles. It is defined as +the sum of min (p1_counter[i] / p1_sum_all, p2_counter[i] / p2_sum_all), +for all arc counter i, where p1_counter[i] and p2_counter[i] are two +matched counters and p1_sum_all and p2_sum_all are the sum of counter +values in profile 1 and profile 2, respectively. + +@table @gcctabopt +@item -v +@itemx --verbose +Set the verbose mode. + +@item -h +@itemx --hotonly +Only print info for hot objects/functions. + +@item -f +@itemx --function +Print function level overlap score. + +@item -F +@itemx --fullname +Print full gcda filename. + +@item -o +@itemx --object +Print object level overlap score. + +@item -t @var{float} +@itemx --hot_threshold +Set the threshold for hot counter value. @end table + @end table @c man end