0f97b532d7f34234d1295ef984a873611b5c4498
[dragonfly.git] / contrib / gcc-5.0 / gcc / gcov-tool.c
1 /* Gcc offline profile processing tool support. */
2 /* Copyright (C) 2014-2015 Free Software Foundation, Inc.
3    Contributed by Rong Xu <xur@google.com>.
4
5 This file is part of GCC.
6
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.
11
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.
16
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.
20
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/>.  */
25
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>
40
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);
48
49 /* Set to verbose output mode.  */
50 static bool verbose;
51
52 /* Remove file NAME if it has a gcda suffix. */
53
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)
59 {
60   int ret = 0;
61   int len = strlen (name);
62   int len1 = strlen (GCOV_DATA_SUFFIX);
63
64   if (len > len1 && !strncmp (len -len1 + name, GCOV_DATA_SUFFIX, len1))
65     ret = remove (name);
66
67   if (ret)
68     fatal_error (input_location, "error in removing %s\n", name);
69
70   return ret;
71 }
72
73 /* Remove the gcda files in PATH recursively.  */
74
75 static int
76 unlink_profile_dir (const char *path)
77 {
78     return nftw(path, unlink_gcda_file, 64, FTW_DEPTH | FTW_PHYS);
79 }
80
81 /* Output GCOV_INFO lists PROFILE to directory OUT. Note that
82    we will remove all the gcda files in OUT.  */
83
84 static void
85 gcov_output_files (const char *out, struct gcov_info *profile)
86 {
87   char *pwd;
88   int ret;
89
90   /* Try to make directory if it doesn't already exist.  */
91   if (access (out, F_OK) == -1)
92     {
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);
101
102   /* Output new profile.  */
103   pwd = getcwd (NULL, 0);
104
105   if (pwd == NULL)
106     fatal_error (input_location, "Cannot get current directory name");
107
108   ret = chdir (out);
109   if (ret)
110     fatal_error (input_location, "Cannot change directory to %s", out);
111
112   gcov_do_dump (profile, 0);
113
114   ret = chdir (pwd);
115   if (ret)
116     fatal_error (input_location, "Cannot change directory to %s", pwd);
117
118   free (pwd);
119 }
120
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.  */
124
125 static int
126 profile_merge (const char *d1, const char *d2, const char *out, int w1, int w2)
127 {
128   struct gcov_info *d1_profile;
129   struct gcov_info *d2_profile;
130   int ret;
131
132   d1_profile = gcov_read_profile_dir (d1, 0);
133   if (!d1_profile)
134     return 1;
135
136   if (d2)
137     {
138       d2_profile = gcov_read_profile_dir (d2, 0);
139       if (!d2_profile)
140         return 1;
141
142       /* The actual merge: we overwrite to d1_profile.  */
143       ret = gcov_profile_merge (d1_profile, d2_profile, w1, w2);
144
145       if (ret)
146         return ret;
147     }
148
149   gcov_output_files (out, d1_profile);
150
151   return 0;
152 }
153
154 /* Usage message for profile merge.  */
155
156 static void
157 print_merge_usage_message (int error_p)
158 {
159   FILE *file = error_p ? stderr : stdout;
160
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");
165 }
166
167 static const struct option merge_options[] =
168 {
169   { "verbose",                no_argument,       NULL, 'v' },
170   { "output",                 required_argument, NULL, 'o' },
171   { "weight",                 required_argument, NULL, 'w' },
172   { 0, 0, 0, 0 }
173 };
174
175 /* Print merge usage and exit.  */
176
177 static void
178 merge_usage (void)
179 {
180   fnotice (stderr, "Merge subcomand usage:");
181   print_merge_usage_message (true);
182   exit (FATAL_EXIT_CODE);
183 }
184
185 /* Driver for profile merge sub-command.  */
186
187 static int
188 do_merge (int argc, char **argv)
189 {
190   int opt;
191   int ret;
192   const char *output_dir = 0;
193   int w1 = 1, w2 = 1;
194
195   optind = 0;
196   while ((opt = getopt_long (argc, argv, "vo:w:", merge_options, NULL)) != -1)
197     {
198       switch (opt)
199         {
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 ();
214         }
215     }
216
217   if (output_dir == NULL)
218     output_dir = "merged_profile";
219
220   if (argc - optind == 2)
221     ret = profile_merge (argv[optind], argv[optind+1], output_dir, w1, w2);
222   else
223     merge_usage ();
224
225   return ret;
226 }
227
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.  */
231
232 static int
233 profile_rewrite (const char *d1, const char *out, long long n_val,
234                  float scale, int n, int d)
235 {
236   struct gcov_info * d1_profile;
237
238   d1_profile = gcov_read_profile_dir (d1, 0);
239   if (!d1_profile)
240     return 1;
241
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);
246
247   gcov_output_files (out, d1_profile);
248   return 0;
249 }
250
251 /* Usage function for profile rewrite.  */
252
253 static void
254 print_rewrite_usage_message (int error_p)
255 {
256   FILE *file = error_p ? stderr : stdout;
257
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");
263 }
264
265 static const struct option rewrite_options[] =
266 {
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 }
272 };
273
274 /* Print profile rewrite usage and exit.  */
275
276 static void
277 rewrite_usage (void)
278 {
279   fnotice (stderr, "Rewrite subcommand usage:");
280   print_rewrite_usage_message (true);
281   exit (FATAL_EXIT_CODE);
282 }
283
284 /* Driver for profile rewrite sub-command. */
285
286 static int
287 do_rewrite (int argc, char **argv)
288 {
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;
301
302   optind = 0;
303   while ((opt = getopt_long (argc, argv, "vo:s:n:", rewrite_options, NULL)) != -1)
304     {
305       switch (opt)
306         {
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, "/"))
331             {
332               ret = sscanf (optarg, "%d/%d", &numerator, &denominator);
333               if (ret == 2)
334                 {
335                   if (numerator < 0 || denominator <= 0)
336                     {
337                       fnotice (stderr, "incorrect format in scaling, using 1/1\n");
338                       denominator = 1;
339                       numerator = 1;
340                     }
341                 }
342             }
343           if (ret != 2)
344             {
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;
350             }
351
352           if (scale < 0.0)
353             fatal_error (input_location, "scale needs to be non-negative\n");
354
355           if (normalize_val != 0)
356             {
357               fnotice (stderr, "normalization cannot co-exist with scaling\n");
358               normalize_val = 0;
359             }
360           break;
361         default:
362           rewrite_usage ();
363         }
364     }
365
366   if (output_dir == NULL)
367     output_dir = "rewrite_profile";
368
369   if (argc - optind == 1)
370     {
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);
375     }
376   else
377     rewrite_usage ();
378
379   return ret;
380 }
381
382 /* Driver function to computer the overlap score b/w profile D1 and D2.
383    Return 1 on error and 0 if OK.  */
384
385 static int
386 profile_overlap (const char *d1, const char *d2)
387 {
388   struct gcov_info *d1_profile;
389   struct gcov_info *d2_profile;
390
391   d1_profile = gcov_read_profile_dir (d1, 0);
392   if (!d1_profile)
393     return 1;
394
395   if (d2)
396     {
397       d2_profile = gcov_read_profile_dir (d2, 0);
398       if (!d2_profile)
399         return 1;
400
401       return gcov_profile_overlap (d1_profile, d2_profile);
402     }
403
404   return 1;
405 }
406
407 /* Usage message for profile overlap.  */
408
409 static void
410 print_overlap_usage_message (int error_p)
411 {
412   FILE *file = error_p ? stderr : stdout;
413
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");
421
422 }
423
424 static const struct option overlap_options[] =
425 {
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 }
433 };
434
435 /* Print overlap usage and exit.  */
436
437 static void
438 overlap_usage (void)
439 {
440   fnotice (stderr, "Overlap subcomand usage:");
441   print_overlap_usage_message (true);
442   exit (FATAL_EXIT_CODE);
443 }
444
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;
450
451 /* Driver for profile overlap sub-command.  */
452
453 static int
454 do_overlap (int argc, char **argv)
455 {
456   int opt;
457   int ret;
458
459   optind = 0;
460   while ((opt = getopt_long (argc, argv, "vfFoht:", overlap_options, NULL)) != -1)
461     {
462       switch (opt)
463         {
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 ();
485         }
486     }
487
488   if (argc - optind == 2)
489     ret = profile_overlap (argv[optind], argv[optind+1]);
490   else
491     overlap_usage ();
492
493   return ret;
494 }
495
496
497 /* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
498    otherwise the output of --help.  */
499
500 static void
501 print_usage (int error_p)
502 {
503   FILE *file = error_p ? stderr : stdout;
504   int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
505
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);
516 }
517
518 /* Print version information and exit.  */
519
520 static void
521 print_version (void)
522 {
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);
531 }
532
533 static const struct option options[] =
534 {
535   { "help",                 no_argument,       NULL, 'h' },
536   { "version",              no_argument,       NULL, 'v' },
537   { 0, 0, 0, 0 }
538 };
539
540 /* Process args, return index to first non-arg.  */
541
542 static int
543 process_args (int argc, char **argv)
544 {
545   int opt;
546
547   while ((opt = getopt_long (argc, argv, "+hv", options, NULL)) != -1)
548     {
549       switch (opt)
550         {
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.  */
560         }
561     }
562
563   return optind;
564 }
565
566 /* Main function for gcov-tool.  */
567
568 int
569 main (int argc, char **argv)
570 {
571   const char *p;
572   const char *sub_command;
573
574   p = argv[0] + strlen (argv[0]);
575   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
576     --p;
577   progname = p;
578
579   xmalloc_set_program_name (progname);
580
581   /* Unlock the stdio streams.  */
582   unlock_std_streams ();
583
584   gcc_init_libintl ();
585
586   diagnostic_initialize (global_dc, 0);
587
588   /* Handle response files.  */
589   expandargv (&argc, &argv);
590
591   process_args (argc, argv);
592   if (optind >= argc)
593     print_usage (true);
594
595   sub_command = argv[optind];
596
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);
603
604   print_usage (true);
605 }