c-common.c (get_source_date_epoch): Use int64_t instead of long long.
[platform/upstream/gcc.git] / gcc / gcov-tool.c
1 /* Gcc offline profile processing tool support. */
2 /* Copyright (C) 2014-2016 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 #if HAVE_FTW_H
39 #include <ftw.h>
40 #endif
41 #include <getopt.h>
42
43 extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int);
44 extern int gcov_profile_overlap (struct gcov_info*, struct gcov_info*);
45 extern int gcov_profile_normalize (struct gcov_info*, gcov_type);
46 extern int gcov_profile_scale (struct gcov_info*, float, int, int);
47 extern struct gcov_info* gcov_read_profile_dir (const char*, int);
48 extern void gcov_do_dump (struct gcov_info *, int);
49 extern void gcov_set_verbose (void);
50
51 /* Set to verbose output mode.  */
52 static bool verbose;
53
54 #if HAVE_FTW_H
55
56 /* Remove file NAME if it has a gcda suffix. */
57
58 static int
59 unlink_gcda_file (const char *name,
60                   const struct stat *status ATTRIBUTE_UNUSED,
61                   int type ATTRIBUTE_UNUSED,
62                   struct FTW *ftwbuf ATTRIBUTE_UNUSED)
63 {
64   int ret = 0;
65   int len = strlen (name);
66   int len1 = strlen (GCOV_DATA_SUFFIX);
67
68   if (len > len1 && !strncmp (len -len1 + name, GCOV_DATA_SUFFIX, len1))
69     ret = remove (name);
70
71   if (ret)
72     fatal_error (input_location, "error in removing %s\n", name);
73
74   return ret;
75 }
76 #endif
77
78 /* Remove the gcda files in PATH recursively.  */
79
80 static int
81 unlink_profile_dir (const char *path ATTRIBUTE_UNUSED)
82 {
83 #if HAVE_FTW_H
84     return nftw(path, unlink_gcda_file, 64, FTW_DEPTH | FTW_PHYS);
85 #else
86     return -1;
87 #endif
88 }
89
90 /* Output GCOV_INFO lists PROFILE to directory OUT. Note that
91    we will remove all the gcda files in OUT.  */
92
93 static void
94 gcov_output_files (const char *out, struct gcov_info *profile)
95 {
96   char *pwd;
97   int ret;
98
99   /* Try to make directory if it doesn't already exist.  */
100   if (access (out, F_OK) == -1)
101     {
102       if (mkdir (out, S_IRWXU | S_IRWXG | S_IRWXO) == -1 && errno != EEXIST)
103         fatal_error (input_location, "Cannot make directory %s", out);
104     } else
105       unlink_profile_dir (out);
106
107   /* Output new profile.  */
108   pwd = getcwd (NULL, 0);
109
110   if (pwd == NULL)
111     fatal_error (input_location, "Cannot get current directory name");
112
113   ret = chdir (out);
114   if (ret)
115     fatal_error (input_location, "Cannot change directory to %s", out);
116
117   gcov_do_dump (profile, 0);
118
119   ret = chdir (pwd);
120   if (ret)
121     fatal_error (input_location, "Cannot change directory to %s", pwd);
122
123   free (pwd);
124 }
125
126 /* Merging profile D1 and D2 with weight as W1 and W2, respectively.
127    The result profile is written to directory OUT.
128    Return 0 on success.  */
129
130 static int
131 profile_merge (const char *d1, const char *d2, const char *out, int w1, int w2)
132 {
133   struct gcov_info *d1_profile;
134   struct gcov_info *d2_profile;
135   int ret;
136
137   d1_profile = gcov_read_profile_dir (d1, 0);
138   if (!d1_profile)
139     return 1;
140
141   if (d2)
142     {
143       d2_profile = gcov_read_profile_dir (d2, 0);
144       if (!d2_profile)
145         return 1;
146
147       /* The actual merge: we overwrite to d1_profile.  */
148       ret = gcov_profile_merge (d1_profile, d2_profile, w1, w2);
149
150       if (ret)
151         return ret;
152     }
153
154   gcov_output_files (out, d1_profile);
155
156   return 0;
157 }
158
159 /* Usage message for profile merge.  */
160
161 static void
162 print_merge_usage_message (int error_p)
163 {
164   FILE *file = error_p ? stderr : stdout;
165
166   fnotice (file, "  merge [options] <dir1> <dir2>         Merge coverage file contents\n");
167   fnotice (file, "    -v, --verbose                       Verbose mode\n");
168   fnotice (file, "    -o, --output <dir>                  Output directory\n");
169   fnotice (file, "    -w, --weight <w1,w2>                Set weights (float point values)\n");
170 }
171
172 static const struct option merge_options[] =
173 {
174   { "verbose",                no_argument,       NULL, 'v' },
175   { "output",                 required_argument, NULL, 'o' },
176   { "weight",                 required_argument, NULL, 'w' },
177   { 0, 0, 0, 0 }
178 };
179
180 /* Print merge usage and exit.  */
181
182 static void
183 merge_usage (void)
184 {
185   fnotice (stderr, "Merge subcomand usage:");
186   print_merge_usage_message (true);
187   exit (FATAL_EXIT_CODE);
188 }
189
190 /* Driver for profile merge sub-command.  */
191
192 static int
193 do_merge (int argc, char **argv)
194 {
195   int opt;
196   const char *output_dir = 0;
197   int w1 = 1, w2 = 1;
198
199   optind = 0;
200   while ((opt = getopt_long (argc, argv, "vo:w:", merge_options, NULL)) != -1)
201     {
202       switch (opt)
203         {
204         case 'v':
205           verbose = true;
206           gcov_set_verbose ();
207           break;
208         case 'o':
209           output_dir = optarg;
210           break;
211         case 'w':
212           sscanf (optarg, "%d,%d", &w1, &w2);
213           if (w1 < 0 || w2 < 0)
214             fatal_error (input_location, "weights need to be non-negative\n");
215           break;
216         default:
217           merge_usage ();
218         }
219     }
220
221   if (output_dir == NULL)
222     output_dir = "merged_profile";
223
224   if (argc - optind != 2)
225     merge_usage ();
226
227   return profile_merge (argv[optind], argv[optind+1], output_dir, w1, w2);
228 }
229
230 /* If N_VAL is no-zero, normalize the profile by setting the largest counter
231    counter value to N_VAL and scale others counters proportionally.
232    Otherwise, multiply the all counters by SCALE.  */
233
234 static int
235 profile_rewrite (const char *d1, const char *out, int64_t n_val,
236                  float scale, int n, int d)
237 {
238   struct gcov_info * d1_profile;
239
240   d1_profile = gcov_read_profile_dir (d1, 0);
241   if (!d1_profile)
242     return 1;
243
244   if (n_val)
245     gcov_profile_normalize (d1_profile, (gcov_type) n_val);
246   else
247     gcov_profile_scale (d1_profile, scale, n, d);
248
249   gcov_output_files (out, d1_profile);
250   return 0;
251 }
252
253 /* Usage function for profile rewrite.  */
254
255 static void
256 print_rewrite_usage_message (int error_p)
257 {
258   FILE *file = error_p ? stderr : stdout;
259
260   fnotice (file, "  rewrite [options] <dir>               Rewrite coverage file contents\n");
261   fnotice (file, "    -v, --verbose                       Verbose mode\n");
262   fnotice (file, "    -o, --output <dir>                  Output directory\n");
263   fnotice (file, "    -s, --scale <float or simple-frac>  Scale the profile counters\n");
264   fnotice (file, "    -n, --normalize <int64_t>           Normalize the profile\n");
265 }
266
267 static const struct option rewrite_options[] =
268 {
269   { "verbose",                no_argument,       NULL, 'v' },
270   { "output",                 required_argument, NULL, 'o' },
271   { "scale",                  required_argument, NULL, 's' },
272   { "normalize",              required_argument, NULL, 'n' },
273   { 0, 0, 0, 0 }
274 };
275
276 /* Print profile rewrite usage and exit.  */
277
278 static void
279 rewrite_usage (void)
280 {
281   fnotice (stderr, "Rewrite subcommand usage:");
282   print_rewrite_usage_message (true);
283   exit (FATAL_EXIT_CODE);
284 }
285
286 /* Driver for profile rewrite sub-command. */
287
288 static int
289 do_rewrite (int argc, char **argv)
290 {
291   int opt;
292   int ret;
293   const char *output_dir = 0;
294   int64_t normalize_val = 0;
295   float scale = 0.0;
296   int numerator = 1;
297   int denominator = 1;
298   int do_scaling = 0;
299
300   optind = 0;
301   while ((opt = getopt_long (argc, argv, "vo:s:n:", rewrite_options, NULL)) != -1)
302     {
303       switch (opt)
304         {
305         case 'v':
306           verbose = true;
307           gcov_set_verbose ();
308           break;
309         case 'o':
310           output_dir = optarg;
311           break;
312         case 'n':
313           if (!do_scaling)
314 #if defined(INT64_T_IS_LONG)
315             normalize_val = strtol (optarg, (char **)NULL, 10);
316 #else
317             normalize_val = strtoll (optarg, (char **)NULL, 10);
318 #endif
319           else
320             fnotice (stderr, "scaling cannot co-exist with normalization,"
321                 " skipping\n");
322           break;
323         case 's':
324           ret = 0;
325           do_scaling = 1;
326           if (strstr (optarg, "/"))
327             {
328               ret = sscanf (optarg, "%d/%d", &numerator, &denominator);
329               if (ret == 2)
330                 {
331                   if (numerator < 0 || denominator <= 0)
332                     {
333                       fnotice (stderr, "incorrect format in scaling, using 1/1\n");
334                       denominator = 1;
335                       numerator = 1;
336                     }
337                 }
338             }
339           if (ret != 2)
340             {
341               ret = sscanf (optarg, "%f", &scale);
342               if (ret != 1)
343                 fnotice (stderr, "incorrect format in scaling, using 1/1\n");
344               else
345                 denominator = 0;
346             }
347
348           if (scale < 0.0)
349             fatal_error (input_location, "scale needs to be non-negative\n");
350
351           if (normalize_val != 0)
352             {
353               fnotice (stderr, "normalization cannot co-exist with scaling\n");
354               normalize_val = 0;
355             }
356           break;
357         default:
358           rewrite_usage ();
359         }
360     }
361
362   if (output_dir == NULL)
363     output_dir = "rewrite_profile";
364
365   if (argc - optind == 1)
366     {
367       if (denominator > 0)
368         ret = profile_rewrite (argv[optind],  output_dir, 0, 0.0, numerator, denominator);
369       else
370         ret = profile_rewrite (argv[optind],  output_dir, normalize_val, scale, 0, 0);
371     }
372   else
373     rewrite_usage ();
374
375   return ret;
376 }
377
378 /* Driver function to computer the overlap score b/w profile D1 and D2.
379    Return 1 on error and 0 if OK.  */
380
381 static int
382 profile_overlap (const char *d1, const char *d2)
383 {
384   struct gcov_info *d1_profile;
385   struct gcov_info *d2_profile;
386
387   d1_profile = gcov_read_profile_dir (d1, 0);
388   if (!d1_profile)
389     return 1;
390
391   if (d2)
392     {
393       d2_profile = gcov_read_profile_dir (d2, 0);
394       if (!d2_profile)
395         return 1;
396
397       return gcov_profile_overlap (d1_profile, d2_profile);
398     }
399
400   return 1;
401 }
402
403 /* Usage message for profile overlap.  */
404
405 static void
406 print_overlap_usage_message (int error_p)
407 {
408   FILE *file = error_p ? stderr : stdout;
409
410   fnotice (file, "  overlap [options] <dir1> <dir2>       Compute the overlap of two profiles\n");
411   fnotice (file, "    -v, --verbose                       Verbose mode\n");
412   fnotice (file, "    -h, --hotonly                       Only print info for hot objects/functions\n");
413   fnotice (file, "    -f, --function                      Print function level info\n");
414   fnotice (file, "    -F, --fullname                      Print full filename\n");
415   fnotice (file, "    -o, --object                        Print object level info\n");
416   fnotice (file, "    -t <float>, --hot_threshold <float> Set the threshold for hotness\n");
417
418 }
419
420 static const struct option overlap_options[] =
421 {
422   { "verbose",                no_argument,       NULL, 'v' },
423   { "function",               no_argument,       NULL, 'f' },
424   { "fullname",               no_argument,       NULL, 'F' },
425   { "object",                 no_argument,       NULL, 'o' },
426   { "hotonly",                no_argument,       NULL, 'h' },
427   { "hot_threshold",          required_argument, NULL, 't' },
428   { 0, 0, 0, 0 }
429 };
430
431 /* Print overlap usage and exit.  */
432
433 static void
434 overlap_usage (void)
435 {
436   fnotice (stderr, "Overlap subcomand usage:");
437   print_overlap_usage_message (true);
438   exit (FATAL_EXIT_CODE);
439 }
440
441 int overlap_func_level;
442 int overlap_obj_level;
443 int overlap_hot_only;
444 int overlap_use_fullname;
445 double overlap_hot_threshold = 0.005;
446
447 /* Driver for profile overlap sub-command.  */
448
449 static int
450 do_overlap (int argc, char **argv)
451 {
452   int opt;
453   int ret;
454
455   optind = 0;
456   while ((opt = getopt_long (argc, argv, "vfFoht:", overlap_options, NULL)) != -1)
457     {
458       switch (opt)
459         {
460         case 'v':
461           verbose = true;
462           gcov_set_verbose ();
463           break;
464         case 'f':
465           overlap_func_level = 1;
466           break;
467         case 'F':
468           overlap_use_fullname = 1;
469           break;
470         case 'o':
471           overlap_obj_level = 1;
472           break;
473         case 'h':
474           overlap_hot_only = 1;
475           break;
476         case 't':
477           overlap_hot_threshold = atof (optarg);
478           break;
479         default:
480           overlap_usage ();
481         }
482     }
483
484   if (argc - optind == 2)
485     ret = profile_overlap (argv[optind], argv[optind+1]);
486   else
487     overlap_usage ();
488
489   return ret;
490 }
491
492
493 /* Print a usage message and exit.  If ERROR_P is nonzero, this is an error,
494    otherwise the output of --help.  */
495
496 static void
497 print_usage (int error_p)
498 {
499   FILE *file = error_p ? stderr : stdout;
500   int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
501
502   fnotice (file, "Usage: %s [OPTION]... SUB_COMMAND [OPTION]...\n\n", progname);
503   fnotice (file, "Offline tool to handle gcda counts\n\n");
504   fnotice (file, "  -h, --help                            Print this help, then exit\n");
505   fnotice (file, "  -v, --version                         Print version number, then exit\n");
506   print_merge_usage_message (error_p);
507   print_rewrite_usage_message (error_p);
508   print_overlap_usage_message (error_p);
509   fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
510            bug_report_url);
511   exit (status);
512 }
513
514 /* Print version information and exit.  */
515
516 static void
517 print_version (void)
518 {
519   fnotice (stdout, "%s %s%s\n", progname, pkgversion_string, version_string);
520   fnotice (stdout, "Copyright %s 2014-2016 Free Software Foundation, Inc.\n",
521            _("(C)"));
522   fnotice (stdout,
523            _("This is free software; see the source for copying conditions.\n"
524              "There is NO warranty; not even for MERCHANTABILITY or \n"
525              "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
526   exit (SUCCESS_EXIT_CODE);
527 }
528
529 static const struct option options[] =
530 {
531   { "help",                 no_argument,       NULL, 'h' },
532   { "version",              no_argument,       NULL, 'v' },
533   { 0, 0, 0, 0 }
534 };
535
536 /* Process args, return index to first non-arg.  */
537
538 static int
539 process_args (int argc, char **argv)
540 {
541   int opt;
542
543   while ((opt = getopt_long (argc, argv, "+hv", options, NULL)) != -1)
544     {
545       switch (opt)
546         {
547         case 'h':
548           print_usage (false);
549           /* Print_usage will exit.  */
550         case 'v':
551           print_version ();
552           /* Print_version will exit.  */
553         default:
554           print_usage (true);
555           /* Print_usage will exit.  */
556         }
557     }
558
559   return optind;
560 }
561
562 /* Main function for gcov-tool.  */
563
564 int
565 main (int argc, char **argv)
566 {
567   const char *p;
568   const char *sub_command;
569
570   p = argv[0] + strlen (argv[0]);
571   while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
572     --p;
573   progname = p;
574
575   xmalloc_set_program_name (progname);
576
577   /* Unlock the stdio streams.  */
578   unlock_std_streams ();
579
580   gcc_init_libintl ();
581
582   diagnostic_initialize (global_dc, 0);
583
584   /* Handle response files.  */
585   expandargv (&argc, &argv);
586
587   process_args (argc, argv);
588   if (optind >= argc)
589     print_usage (true);
590
591   sub_command = argv[optind];
592
593   if (!strcmp (sub_command, "merge"))
594     return do_merge (argc - optind, argv + optind);
595   else if (!strcmp (sub_command, "rewrite"))
596     return do_rewrite (argc - optind, argv + optind);
597   else if (!strcmp (sub_command, "overlap"))
598     return do_overlap (argc - optind, argv + optind);
599
600   print_usage (true);
601 }