1 /* Gcc offline profile processing tool support. */
2 /* Copyright (C) 2014 Free Software Foundation, Inc.
3 Contributed by Rong Xu <xur@google.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
28 #include "coretypes.h"
31 #include "diagnostic.h"
41 extern int gcov_profile_merge (struct gcov_info
*, struct gcov_info
*, int, int);
42 extern int gcov_profile_overlap (struct gcov_info
*, struct gcov_info
*);
43 extern int gcov_profile_normalize (struct gcov_info
*, gcov_type
);
44 extern int gcov_profile_scale (struct gcov_info
*, float, int, int);
45 extern struct gcov_info
* gcov_read_profile_dir (const char*, int);
46 extern void gcov_do_dump (struct gcov_info
*, int);
47 extern void gcov_set_verbose (void);
49 /* Set to verbose output mode. */
52 /* Remove file NAME if it has a gcda suffix. */
55 unlink_gcda_file (const char *name
,
56 const struct stat
*status ATTRIBUTE_UNUSED
,
57 int type ATTRIBUTE_UNUSED
,
58 struct FTW
*ftwbuf ATTRIBUTE_UNUSED
)
61 int len
= strlen (name
);
62 int len1
= strlen (GCOV_DATA_SUFFIX
);
64 if (len
> len1
&& !strncmp (len
-len1
+ name
, GCOV_DATA_SUFFIX
, len1
))
68 fatal_error ("error in removing %s\n", name
);
73 /* Remove the gcda files in PATH recursively. */
76 unlink_profile_dir (const char *path
)
78 return nftw(path
, unlink_gcda_file
, 64, FTW_DEPTH
| FTW_PHYS
);
81 /* Output GCOV_INFO lists PROFILE to directory OUT. Note that
82 we will remove all the gcda files in OUT. */
85 gcov_output_files (const char *out
, struct gcov_info
*profile
)
90 /* Try to make directory if it doesn't already exist. */
91 if (access (out
, F_OK
) == -1)
94 if (mkdir (out
, S_IRWXU
| S_IRWXG
| S_IRWXO
) == -1 && errno
!= EEXIST
)
96 if (mkdir (out
) == -1 && errno
!= EEXIST
)
98 fatal_error ("Cannot make directory %s", out
);
100 unlink_profile_dir (out
);
102 /* Output new profile. */
103 pwd
= getcwd (NULL
, 0);
106 fatal_error ("Cannot get current directory name");
110 fatal_error ("Cannot change directory to %s", out
);
112 gcov_do_dump (profile
, 0);
116 fatal_error ("Cannot change directory to %s", pwd
);
121 /* Merging profile D1 and D2 with weight as W1 and W2, respectively.
122 The result profile is written to directory OUT.
123 Return 0 on success. */
126 profile_merge (const char *d1
, const char *d2
, const char *out
, int w1
, int w2
)
128 struct gcov_info
*d1_profile
;
129 struct gcov_info
*d2_profile
;
132 d1_profile
= gcov_read_profile_dir (d1
, 0);
138 d2_profile
= gcov_read_profile_dir (d2
, 0);
142 /* The actual merge: we overwrite to d1_profile. */
143 ret
= gcov_profile_merge (d1_profile
, d2_profile
, w1
, w2
);
149 gcov_output_files (out
, d1_profile
);
154 /* Usage message for profile merge. */
157 print_merge_usage_message (int error_p
)
159 FILE *file
= error_p
? stderr
: stdout
;
161 fnotice (file
, " merge [options] <dir1> <dir2> Merge coverage file contents\n");
162 fnotice (file
, " -v, --verbose Verbose mode\n");
163 fnotice (file
, " -o, --output <dir> Output directory\n");
164 fnotice (file
, " -w, --weight <w1,w2> Set weights (float point values)\n");
167 static const struct option merge_options
[] =
169 { "verbose", no_argument
, NULL
, 'v' },
170 { "output", required_argument
, NULL
, 'o' },
171 { "weight", required_argument
, NULL
, 'w' },
175 /* Print merge usage and exit. */
180 fnotice (stderr
, "Merge subcomand usage:");
181 print_merge_usage_message (true);
182 exit (FATAL_EXIT_CODE
);
185 /* Driver for profile merge sub-command. */
188 do_merge (int argc
, char **argv
)
192 const char *output_dir
= 0;
196 while ((opt
= getopt_long (argc
, argv
, "vo:w:", merge_options
, NULL
)) != -1)
208 sscanf (optarg
, "%d,%d", &w1
, &w2
);
209 if (w1
< 0 || w2
< 0)
210 fatal_error ("weights need to be non-negative\n");
217 if (output_dir
== NULL
)
218 output_dir
= "merged_profile";
220 if (argc
- optind
== 2)
221 ret
= profile_merge (argv
[optind
], argv
[optind
+1], output_dir
, w1
, w2
);
228 /* If N_VAL is no-zero, normalize the profile by setting the largest counter
229 counter value to N_VAL and scale others counters proportionally.
230 Otherwise, multiply the all counters by SCALE. */
233 profile_rewrite (const char *d1
, const char *out
, long long n_val
,
234 float scale
, int n
, int d
)
236 struct gcov_info
* d1_profile
;
238 d1_profile
= gcov_read_profile_dir (d1
, 0);
243 gcov_profile_normalize (d1_profile
, (gcov_type
) n_val
);
245 gcov_profile_scale (d1_profile
, scale
, n
, d
);
247 gcov_output_files (out
, d1_profile
);
251 /* Usage function for profile rewrite. */
254 print_rewrite_usage_message (int error_p
)
256 FILE *file
= error_p
? stderr
: stdout
;
258 fnotice (file
, " rewrite [options] <dir> Rewrite coverage file contents\n");
259 fnotice (file
, " -v, --verbose Verbose mode\n");
260 fnotice (file
, " -o, --output <dir> Output directory\n");
261 fnotice (file
, " -s, --scale <float or simple-frac> Scale the profile counters\n");
262 fnotice (file
, " -n, --normalize <long long> Normalize the profile\n");
265 static const struct option rewrite_options
[] =
267 { "verbose", no_argument
, NULL
, 'v' },
268 { "output", required_argument
, NULL
, 'o' },
269 { "scale", required_argument
, NULL
, 's' },
270 { "normalize", required_argument
, NULL
, 'n' },
274 /* Print profile rewrite usage and exit. */
279 fnotice (stderr
, "Rewrite subcommand usage:");
280 print_rewrite_usage_message (true);
281 exit (FATAL_EXIT_CODE
);
284 /* Driver for profile rewrite sub-command. */
287 do_rewrite (int argc
, char **argv
)
291 const char *output_dir
= 0;
292 long long normalize_val
= 0;
299 while ((opt
= getopt_long (argc
, argv
, "vo:s:n:", rewrite_options
, NULL
)) != -1)
312 normalize_val
= atoll (optarg
);
314 fnotice (stderr
, "scaling cannot co-exist with normalization,"
320 if (strstr (optarg
, "/"))
322 ret
= sscanf (optarg
, "%d/%d", &numerator
, &denominator
);
325 if (numerator
< 0 || denominator
<= 0)
327 fnotice (stderr
, "incorrect format in scaling, using 1/1\n");
335 ret
= sscanf (optarg
, "%f", &scale
);
337 fnotice (stderr
, "incorrect format in scaling, using 1/1\n");
343 fatal_error ("scale needs to be non-negative\n");
345 if (normalize_val
!= 0)
347 fnotice (stderr
, "normalization cannot co-exist with scaling\n");
356 if (output_dir
== NULL
)
357 output_dir
= "rewrite_profile";
359 if (argc
- optind
== 1)
362 ret
= profile_rewrite (argv
[optind
], output_dir
, 0, 0.0, numerator
, denominator
);
364 ret
= profile_rewrite (argv
[optind
], output_dir
, normalize_val
, scale
, 0, 0);
372 /* Driver function to computer the overlap score b/w profile D1 and D2.
373 Return 1 on error and 0 if OK. */
376 profile_overlap (const char *d1
, const char *d2
)
378 struct gcov_info
*d1_profile
;
379 struct gcov_info
*d2_profile
;
381 d1_profile
= gcov_read_profile_dir (d1
, 0);
387 d2_profile
= gcov_read_profile_dir (d2
, 0);
391 return gcov_profile_overlap (d1_profile
, d2_profile
);
397 /* Usage message for profile overlap. */
400 print_overlap_usage_message (int error_p
)
402 FILE *file
= error_p
? stderr
: stdout
;
404 fnotice (file
, " overlap [options] <dir1> <dir2> Compute the overlap of two profiles\n");
405 fnotice (file
, " -v, --verbose Verbose mode\n");
406 fnotice (file
, " -h, --hotonly Only print info for hot objects/functions\n");
407 fnotice (file
, " -f, --function Print function level info\n");
408 fnotice (file
, " -F, --fullname Print full filename\n");
409 fnotice (file
, " -o, --object Print object level info\n");
410 fnotice (file
, " -t <float>, --hot_threshold <float> Set the threshold for hotness\n");
414 static const struct option overlap_options
[] =
416 { "verbose", no_argument
, NULL
, 'v' },
417 { "function", no_argument
, NULL
, 'f' },
418 { "fullname", no_argument
, NULL
, 'F' },
419 { "object", no_argument
, NULL
, 'o' },
420 { "hotonly", no_argument
, NULL
, 'h' },
421 { "hot_threshold", required_argument
, NULL
, 't' },
425 /* Print overlap usage and exit. */
430 fnotice (stderr
, "Overlap subcomand usage:");
431 print_overlap_usage_message (true);
432 exit (FATAL_EXIT_CODE
);
435 int overlap_func_level
;
436 int overlap_obj_level
;
437 int overlap_hot_only
;
438 int overlap_use_fullname
;
439 double overlap_hot_threshold
= 0.005;
441 /* Driver for profile overlap sub-command. */
444 do_overlap (int argc
, char **argv
)
450 while ((opt
= getopt_long (argc
, argv
, "vfFoht:", overlap_options
, NULL
)) != -1)
459 overlap_func_level
= 1;
462 overlap_use_fullname
= 1;
465 overlap_obj_level
= 1;
468 overlap_hot_only
= 1;
471 overlap_hot_threshold
= atof (optarg
);
478 if (argc
- optind
== 2)
479 ret
= profile_overlap (argv
[optind
], argv
[optind
+1]);
487 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
488 otherwise the output of --help. */
491 print_usage (int error_p
)
493 FILE *file
= error_p
? stderr
: stdout
;
494 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
496 fnotice (file
, "Usage: %s [OPTION]... SUB_COMMAND [OPTION]...\n\n", progname
);
497 fnotice (file
, "Offline tool to handle gcda counts\n\n");
498 fnotice (file
, " -h, --help Print this help, then exit\n");
499 fnotice (file
, " -v, --version Print version number, then exit\n");
500 print_merge_usage_message (error_p
);
501 print_rewrite_usage_message (error_p
);
502 print_overlap_usage_message (error_p
);
503 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
508 /* Print version information and exit. */
513 fnotice (stdout
, "%s %s%s\n", progname
, pkgversion_string
, version_string
);
514 fnotice (stdout
, "Copyright %s 2014 Free Software Foundation, Inc.\n",
517 _("This is free software; see the source for copying conditions.\n"
518 "There is NO warranty; not even for MERCHANTABILITY or \n"
519 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
520 exit (SUCCESS_EXIT_CODE
);
523 static const struct option options
[] =
525 { "help", no_argument
, NULL
, 'h' },
526 { "version", no_argument
, NULL
, 'v' },
530 /* Process args, return index to first non-arg. */
533 process_args (int argc
, char **argv
)
537 while ((opt
= getopt_long (argc
, argv
, "+hv", options
, NULL
)) != -1)
543 /* Print_usage will exit. */
546 /* Print_version will exit. */
549 /* Print_usage will exit. */
556 /* Main function for gcov-tool. */
559 main (int argc
, char **argv
)
562 const char *sub_command
;
564 p
= argv
[0] + strlen (argv
[0]);
565 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
569 xmalloc_set_program_name (progname
);
571 /* Unlock the stdio streams. */
572 unlock_std_streams ();
576 diagnostic_initialize (global_dc
, 0);
578 /* Handle response files. */
579 expandargv (&argc
, &argv
);
581 process_args (argc
, argv
);
585 sub_command
= argv
[optind
];
587 if (!strcmp (sub_command
, "merge"))
588 return do_merge (argc
- optind
, argv
+ optind
);
589 else if (!strcmp (sub_command
, "rewrite"))
590 return do_rewrite (argc
- optind
, argv
+ optind
);
591 else if (!strcmp (sub_command
, "overlap"))
592 return do_overlap (argc
- optind
, argv
+ optind
);