mksysinfo.sh: Remove _zone_net_addr_t handling.
[official-gcc.git] / gcc / gcov-tool.c
blob0f97b532d7f34234d1295ef984a873611b5c4498
1 /* Gcc offline profile processing tool support. */
2 /* Copyright (C) 2014-2015 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
10 version.
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
15 for more details.
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/>. */
26 #include "config.h"
27 #include "system.h"
28 #include "coretypes.h"
29 #include "tm.h"
30 #include "intl.h"
31 #include "diagnostic.h"
32 #include "version.h"
33 #include "gcov-io.h"
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <ftw.h>
39 #include <getopt.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. */
50 static bool verbose;
52 /* Remove file NAME if it has a gcda suffix. */
54 static int
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)
60 int ret = 0;
61 int len = strlen (name);
62 int len1 = strlen (GCOV_DATA_SUFFIX);
64 if (len > len1 && !strncmp (len -len1 + name, GCOV_DATA_SUFFIX, len1))
65 ret = remove (name);
67 if (ret)
68 fatal_error (input_location, "error in removing %s\n", name);
70 return ret;
73 /* Remove the gcda files in PATH recursively. */
75 static int
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. */
84 static void
85 gcov_output_files (const char *out, struct gcov_info *profile)
87 char *pwd;
88 int ret;
90 /* Try to make directory if it doesn't already exist. */
91 if (access (out, F_OK) == -1)
93 #if !defined(_WIN32)
94 if (mkdir (out, S_IRWXU | S_IRWXG | S_IRWXO) == -1 && errno != EEXIST)
95 #else
96 if (mkdir (out) == -1 && errno != EEXIST)
97 #endif
98 fatal_error (input_location, "Cannot make directory %s", out);
99 } else
100 unlink_profile_dir (out);
102 /* Output new profile. */
103 pwd = getcwd (NULL, 0);
105 if (pwd == NULL)
106 fatal_error (input_location, "Cannot get current directory name");
108 ret = chdir (out);
109 if (ret)
110 fatal_error (input_location, "Cannot change directory to %s", out);
112 gcov_do_dump (profile, 0);
114 ret = chdir (pwd);
115 if (ret)
116 fatal_error (input_location, "Cannot change directory to %s", pwd);
118 free (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. */
125 static int
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;
130 int ret;
132 d1_profile = gcov_read_profile_dir (d1, 0);
133 if (!d1_profile)
134 return 1;
136 if (d2)
138 d2_profile = gcov_read_profile_dir (d2, 0);
139 if (!d2_profile)
140 return 1;
142 /* The actual merge: we overwrite to d1_profile. */
143 ret = gcov_profile_merge (d1_profile, d2_profile, w1, w2);
145 if (ret)
146 return ret;
149 gcov_output_files (out, d1_profile);
151 return 0;
154 /* Usage message for profile merge. */
156 static void
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' },
172 { 0, 0, 0, 0 }
175 /* Print merge usage and exit. */
177 static void
178 merge_usage (void)
180 fnotice (stderr, "Merge subcomand usage:");
181 print_merge_usage_message (true);
182 exit (FATAL_EXIT_CODE);
185 /* Driver for profile merge sub-command. */
187 static int
188 do_merge (int argc, char **argv)
190 int opt;
191 int ret;
192 const char *output_dir = 0;
193 int w1 = 1, w2 = 1;
195 optind = 0;
196 while ((opt = getopt_long (argc, argv, "vo:w:", merge_options, NULL)) != -1)
198 switch (opt)
200 case 'v':
201 verbose = true;
202 gcov_set_verbose ();
203 break;
204 case 'o':
205 output_dir = optarg;
206 break;
207 case 'w':
208 sscanf (optarg, "%d,%d", &w1, &w2);
209 if (w1 < 0 || w2 < 0)
210 fatal_error (input_location, "weights need to be non-negative\n");
211 break;
212 default:
213 merge_usage ();
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);
222 else
223 merge_usage ();
225 return ret;
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. */
232 static int
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);
239 if (!d1_profile)
240 return 1;
242 if (n_val)
243 gcov_profile_normalize (d1_profile, (gcov_type) n_val);
244 else
245 gcov_profile_scale (d1_profile, scale, n, d);
247 gcov_output_files (out, d1_profile);
248 return 0;
251 /* Usage function for profile rewrite. */
253 static void
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' },
271 { 0, 0, 0, 0 }
274 /* Print profile rewrite usage and exit. */
276 static void
277 rewrite_usage (void)
279 fnotice (stderr, "Rewrite subcommand usage:");
280 print_rewrite_usage_message (true);
281 exit (FATAL_EXIT_CODE);
284 /* Driver for profile rewrite sub-command. */
286 static int
287 do_rewrite (int argc, char **argv)
289 int opt;
290 int ret;
291 const char *output_dir = 0;
292 #ifdef HAVE_LONG_LONG
293 long long normalize_val = 0;
294 #else
295 int64_t normalize_val = 0;
296 #endif
297 float scale = 0.0;
298 int numerator = 1;
299 int denominator = 1;
300 int do_scaling = 0;
302 optind = 0;
303 while ((opt = getopt_long (argc, argv, "vo:s:n:", rewrite_options, NULL)) != -1)
305 switch (opt)
307 case 'v':
308 verbose = true;
309 gcov_set_verbose ();
310 break;
311 case 'o':
312 output_dir = optarg;
313 break;
314 case 'n':
315 if (!do_scaling)
316 #if defined(HAVE_LONG_LONG)
317 normalize_val = strtoll (optarg, (char **)NULL, 10);
318 #elif defined(INT64_T_IS_LONG)
319 normalize_val = strtol (optarg, (char **)NULL, 10);
320 #else
321 sscanf (optarg, "%" SCNd64, &normalize_val);
322 #endif
323 else
324 fnotice (stderr, "scaling cannot co-exist with normalization,"
325 " skipping\n");
326 break;
327 case 's':
328 ret = 0;
329 do_scaling = 1;
330 if (strstr (optarg, "/"))
332 ret = sscanf (optarg, "%d/%d", &numerator, &denominator);
333 if (ret == 2)
335 if (numerator < 0 || denominator <= 0)
337 fnotice (stderr, "incorrect format in scaling, using 1/1\n");
338 denominator = 1;
339 numerator = 1;
343 if (ret != 2)
345 ret = sscanf (optarg, "%f", &scale);
346 if (ret != 1)
347 fnotice (stderr, "incorrect format in scaling, using 1/1\n");
348 else
349 denominator = 0;
352 if (scale < 0.0)
353 fatal_error (input_location, "scale needs to be non-negative\n");
355 if (normalize_val != 0)
357 fnotice (stderr, "normalization cannot co-exist with scaling\n");
358 normalize_val = 0;
360 break;
361 default:
362 rewrite_usage ();
366 if (output_dir == NULL)
367 output_dir = "rewrite_profile";
369 if (argc - optind == 1)
371 if (denominator > 0)
372 ret = profile_rewrite (argv[optind], output_dir, 0, 0.0, numerator, denominator);
373 else
374 ret = profile_rewrite (argv[optind], output_dir, normalize_val, scale, 0, 0);
376 else
377 rewrite_usage ();
379 return ret;
382 /* Driver function to computer the overlap score b/w profile D1 and D2.
383 Return 1 on error and 0 if OK. */
385 static int
386 profile_overlap (const char *d1, const char *d2)
388 struct gcov_info *d1_profile;
389 struct gcov_info *d2_profile;
391 d1_profile = gcov_read_profile_dir (d1, 0);
392 if (!d1_profile)
393 return 1;
395 if (d2)
397 d2_profile = gcov_read_profile_dir (d2, 0);
398 if (!d2_profile)
399 return 1;
401 return gcov_profile_overlap (d1_profile, d2_profile);
404 return 1;
407 /* Usage message for profile overlap. */
409 static void
410 print_overlap_usage_message (int error_p)
412 FILE *file = error_p ? stderr : stdout;
414 fnotice (file, " overlap [options] <dir1> <dir2> Compute the overlap of two profiles\n");
415 fnotice (file, " -v, --verbose Verbose mode\n");
416 fnotice (file, " -h, --hotonly Only print info for hot objects/functions\n");
417 fnotice (file, " -f, --function Print function level info\n");
418 fnotice (file, " -F, --fullname Print full filename\n");
419 fnotice (file, " -o, --object Print object level info\n");
420 fnotice (file, " -t <float>, --hot_threshold <float> Set the threshold for hotness\n");
424 static const struct option overlap_options[] =
426 { "verbose", no_argument, NULL, 'v' },
427 { "function", no_argument, NULL, 'f' },
428 { "fullname", no_argument, NULL, 'F' },
429 { "object", no_argument, NULL, 'o' },
430 { "hotonly", no_argument, NULL, 'h' },
431 { "hot_threshold", required_argument, NULL, 't' },
432 { 0, 0, 0, 0 }
435 /* Print overlap usage and exit. */
437 static void
438 overlap_usage (void)
440 fnotice (stderr, "Overlap subcomand usage:");
441 print_overlap_usage_message (true);
442 exit (FATAL_EXIT_CODE);
445 int overlap_func_level;
446 int overlap_obj_level;
447 int overlap_hot_only;
448 int overlap_use_fullname;
449 double overlap_hot_threshold = 0.005;
451 /* Driver for profile overlap sub-command. */
453 static int
454 do_overlap (int argc, char **argv)
456 int opt;
457 int ret;
459 optind = 0;
460 while ((opt = getopt_long (argc, argv, "vfFoht:", overlap_options, NULL)) != -1)
462 switch (opt)
464 case 'v':
465 verbose = true;
466 gcov_set_verbose ();
467 break;
468 case 'f':
469 overlap_func_level = 1;
470 break;
471 case 'F':
472 overlap_use_fullname = 1;
473 break;
474 case 'o':
475 overlap_obj_level = 1;
476 break;
477 case 'h':
478 overlap_hot_only = 1;
479 break;
480 case 't':
481 overlap_hot_threshold = atof (optarg);
482 break;
483 default:
484 overlap_usage ();
488 if (argc - optind == 2)
489 ret = profile_overlap (argv[optind], argv[optind+1]);
490 else
491 overlap_usage ();
493 return ret;
497 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
498 otherwise the output of --help. */
500 static void
501 print_usage (int error_p)
503 FILE *file = error_p ? stderr : stdout;
504 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
506 fnotice (file, "Usage: %s [OPTION]... SUB_COMMAND [OPTION]...\n\n", progname);
507 fnotice (file, "Offline tool to handle gcda counts\n\n");
508 fnotice (file, " -h, --help Print this help, then exit\n");
509 fnotice (file, " -v, --version Print version number, then exit\n");
510 print_merge_usage_message (error_p);
511 print_rewrite_usage_message (error_p);
512 print_overlap_usage_message (error_p);
513 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
514 bug_report_url);
515 exit (status);
518 /* Print version information and exit. */
520 static void
521 print_version (void)
523 fnotice (stdout, "%s %s%s\n", progname, pkgversion_string, version_string);
524 fnotice (stdout, "Copyright %s 2014-2015 Free Software Foundation, Inc.\n",
525 _("(C)"));
526 fnotice (stdout,
527 _("This is free software; see the source for copying conditions.\n"
528 "There is NO warranty; not even for MERCHANTABILITY or \n"
529 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
530 exit (SUCCESS_EXIT_CODE);
533 static const struct option options[] =
535 { "help", no_argument, NULL, 'h' },
536 { "version", no_argument, NULL, 'v' },
537 { 0, 0, 0, 0 }
540 /* Process args, return index to first non-arg. */
542 static int
543 process_args (int argc, char **argv)
545 int opt;
547 while ((opt = getopt_long (argc, argv, "+hv", options, NULL)) != -1)
549 switch (opt)
551 case 'h':
552 print_usage (false);
553 /* Print_usage will exit. */
554 case 'v':
555 print_version ();
556 /* Print_version will exit. */
557 default:
558 print_usage (true);
559 /* Print_usage will exit. */
563 return optind;
566 /* Main function for gcov-tool. */
569 main (int argc, char **argv)
571 const char *p;
572 const char *sub_command;
574 p = argv[0] + strlen (argv[0]);
575 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
576 --p;
577 progname = p;
579 xmalloc_set_program_name (progname);
581 /* Unlock the stdio streams. */
582 unlock_std_streams ();
584 gcc_init_libintl ();
586 diagnostic_initialize (global_dc, 0);
588 /* Handle response files. */
589 expandargv (&argc, &argv);
591 process_args (argc, argv);
592 if (optind >= argc)
593 print_usage (true);
595 sub_command = argv[optind];
597 if (!strcmp (sub_command, "merge"))
598 return do_merge (argc - optind, argv + optind);
599 else if (!strcmp (sub_command, "rewrite"))
600 return do_rewrite (argc - optind, argv + optind);
601 else if (!strcmp (sub_command, "overlap"))
602 return do_overlap (argc - optind, argv + optind);
604 print_usage (true);