]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/gcov-tool.c
Daily bump.
[thirdparty/gcc.git] / gcc / gcov-tool.c
CommitLineData
c77556a5 1/* Gcc offline profile processing tool support. */
21fa2a29 2/* Copyright (C) 2014-2016 Free Software Foundation, Inc.
c77556a5
RX
3 Contributed by Rong Xu <xur@google.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17Under Section 7 of GPL version 3, you are granted additional
18permissions described in the GCC Runtime Library Exception, version
193.1, as published by the Free Software Foundation.
20
21You should have received a copy of the GNU General Public License and
22a copy of the GCC Runtime Library Exception along with this program;
23see 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>
37050045 38#if HAVE_FTW_H
c77556a5 39#include <ftw.h>
37050045 40#endif
c77556a5
RX
41#include <getopt.h>
42
43extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int);
9b84e7a8 44extern int gcov_profile_overlap (struct gcov_info*, struct gcov_info*);
c77556a5
RX
45extern int gcov_profile_normalize (struct gcov_info*, gcov_type);
46extern int gcov_profile_scale (struct gcov_info*, float, int, int);
47extern struct gcov_info* gcov_read_profile_dir (const char*, int);
19926161 48extern void gcov_do_dump (struct gcov_info *, int);
c77556a5
RX
49extern void gcov_set_verbose (void);
50
51/* Set to verbose output mode. */
52static bool verbose;
53
37050045
TS
54#if HAVE_FTW_H
55
c77556a5
RX
56/* Remove file NAME if it has a gcda suffix. */
57
58static int
59unlink_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)
40fecdd6 72 fatal_error (input_location, "error in removing %s\n", name);
c77556a5
RX
73
74 return ret;
75}
37050045 76#endif
c77556a5
RX
77
78/* Remove the gcda files in PATH recursively. */
79
80static int
37050045 81unlink_profile_dir (const char *path ATTRIBUTE_UNUSED)
c77556a5 82{
37050045 83#if HAVE_FTW_H
c77556a5 84 return nftw(path, unlink_gcda_file, 64, FTW_DEPTH | FTW_PHYS);
37050045
TS
85#else
86 return -1;
87#endif
c77556a5
RX
88}
89
90/* Output GCOV_INFO lists PROFILE to directory OUT. Note that
91 we will remove all the gcda files in OUT. */
92
93static void
94gcov_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 {
68f68004 102 if (mkdir (out, S_IRWXU | S_IRWXG | S_IRWXO) == -1 && errno != EEXIST)
40fecdd6 103 fatal_error (input_location, "Cannot make directory %s", out);
c77556a5
RX
104 } else
105 unlink_profile_dir (out);
106
107 /* Output new profile. */
108 pwd = getcwd (NULL, 0);
109
110 if (pwd == NULL)
40fecdd6 111 fatal_error (input_location, "Cannot get current directory name");
c77556a5
RX
112
113 ret = chdir (out);
114 if (ret)
40fecdd6 115 fatal_error (input_location, "Cannot change directory to %s", out);
c77556a5 116
19926161 117 gcov_do_dump (profile, 0);
c77556a5
RX
118
119 ret = chdir (pwd);
120 if (ret)
40fecdd6 121 fatal_error (input_location, "Cannot change directory to %s", pwd);
c77556a5
RX
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
130static int
131profile_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
161static void
162print_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
172static 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
182static void
183merge_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
192static int
193do_merge (int argc, char **argv)
194{
195 int opt;
c77556a5
RX
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)
40fecdd6 214 fatal_error (input_location, "weights need to be non-negative\n");
c77556a5
RX
215 break;
216 default:
217 merge_usage ();
218 }
219 }
220
221 if (output_dir == NULL)
222 output_dir = "merged_profile";
223
d57c9945 224 if (argc - optind != 2)
c77556a5
RX
225 merge_usage ();
226
d57c9945 227 return profile_merge (argv[optind], argv[optind+1], output_dir, w1, w2);
c77556a5
RX
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
234static int
235profile_rewrite (const char *d1, const char *out, long long 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
255static void
256print_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 <long long> Normalize the profile\n");
265}
266
267static 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
278static void
279rewrite_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
288static int
289do_rewrite (int argc, char **argv)
290{
291 int opt;
292 int ret;
293 const char *output_dir = 0;
e608ef6d 294#ifdef HAVE_LONG_LONG
c77556a5 295 long long normalize_val = 0;
e608ef6d
JDA
296#else
297 int64_t normalize_val = 0;
298#endif
c77556a5
RX
299 float scale = 0.0;
300 int numerator = 1;
301 int denominator = 1;
302 int do_scaling = 0;
303
304 optind = 0;
305 while ((opt = getopt_long (argc, argv, "vo:s:n:", rewrite_options, NULL)) != -1)
306 {
307 switch (opt)
308 {
309 case 'v':
310 verbose = true;
311 gcov_set_verbose ();
312 break;
313 case 'o':
314 output_dir = optarg;
315 break;
316 case 'n':
317 if (!do_scaling)
e608ef6d
JDA
318#if defined(HAVE_LONG_LONG)
319 normalize_val = strtoll (optarg, (char **)NULL, 10);
320#elif defined(INT64_T_IS_LONG)
321 normalize_val = strtol (optarg, (char **)NULL, 10);
322#else
323 sscanf (optarg, "%" SCNd64, &normalize_val);
324#endif
c77556a5
RX
325 else
326 fnotice (stderr, "scaling cannot co-exist with normalization,"
327 " skipping\n");
328 break;
329 case 's':
330 ret = 0;
331 do_scaling = 1;
332 if (strstr (optarg, "/"))
333 {
334 ret = sscanf (optarg, "%d/%d", &numerator, &denominator);
335 if (ret == 2)
336 {
337 if (numerator < 0 || denominator <= 0)
338 {
339 fnotice (stderr, "incorrect format in scaling, using 1/1\n");
340 denominator = 1;
341 numerator = 1;
342 }
343 }
344 }
345 if (ret != 2)
346 {
347 ret = sscanf (optarg, "%f", &scale);
348 if (ret != 1)
349 fnotice (stderr, "incorrect format in scaling, using 1/1\n");
350 else
351 denominator = 0;
352 }
353
354 if (scale < 0.0)
40fecdd6 355 fatal_error (input_location, "scale needs to be non-negative\n");
c77556a5
RX
356
357 if (normalize_val != 0)
358 {
359 fnotice (stderr, "normalization cannot co-exist with scaling\n");
360 normalize_val = 0;
361 }
362 break;
363 default:
364 rewrite_usage ();
365 }
366 }
367
368 if (output_dir == NULL)
369 output_dir = "rewrite_profile";
370
371 if (argc - optind == 1)
372 {
373 if (denominator > 0)
374 ret = profile_rewrite (argv[optind], output_dir, 0, 0.0, numerator, denominator);
375 else
376 ret = profile_rewrite (argv[optind], output_dir, normalize_val, scale, 0, 0);
377 }
378 else
379 rewrite_usage ();
380
381 return ret;
382}
383
9b84e7a8
RX
384/* Driver function to computer the overlap score b/w profile D1 and D2.
385 Return 1 on error and 0 if OK. */
386
387static int
388profile_overlap (const char *d1, const char *d2)
389{
390 struct gcov_info *d1_profile;
391 struct gcov_info *d2_profile;
392
393 d1_profile = gcov_read_profile_dir (d1, 0);
394 if (!d1_profile)
395 return 1;
396
397 if (d2)
398 {
399 d2_profile = gcov_read_profile_dir (d2, 0);
400 if (!d2_profile)
401 return 1;
402
403 return gcov_profile_overlap (d1_profile, d2_profile);
404 }
405
406 return 1;
407}
408
409/* Usage message for profile overlap. */
410
411static void
412print_overlap_usage_message (int error_p)
413{
414 FILE *file = error_p ? stderr : stdout;
415
416 fnotice (file, " overlap [options] <dir1> <dir2> Compute the overlap of two profiles\n");
417 fnotice (file, " -v, --verbose Verbose mode\n");
418 fnotice (file, " -h, --hotonly Only print info for hot objects/functions\n");
419 fnotice (file, " -f, --function Print function level info\n");
420 fnotice (file, " -F, --fullname Print full filename\n");
421 fnotice (file, " -o, --object Print object level info\n");
422 fnotice (file, " -t <float>, --hot_threshold <float> Set the threshold for hotness\n");
423
424}
425
426static const struct option overlap_options[] =
427{
428 { "verbose", no_argument, NULL, 'v' },
429 { "function", no_argument, NULL, 'f' },
430 { "fullname", no_argument, NULL, 'F' },
431 { "object", no_argument, NULL, 'o' },
432 { "hotonly", no_argument, NULL, 'h' },
433 { "hot_threshold", required_argument, NULL, 't' },
434 { 0, 0, 0, 0 }
435};
436
437/* Print overlap usage and exit. */
438
439static void
440overlap_usage (void)
441{
442 fnotice (stderr, "Overlap subcomand usage:");
443 print_overlap_usage_message (true);
444 exit (FATAL_EXIT_CODE);
445}
446
447int overlap_func_level;
448int overlap_obj_level;
449int overlap_hot_only;
450int overlap_use_fullname;
451double overlap_hot_threshold = 0.005;
452
453/* Driver for profile overlap sub-command. */
454
455static int
456do_overlap (int argc, char **argv)
457{
458 int opt;
459 int ret;
460
461 optind = 0;
462 while ((opt = getopt_long (argc, argv, "vfFoht:", overlap_options, NULL)) != -1)
463 {
464 switch (opt)
465 {
466 case 'v':
467 verbose = true;
468 gcov_set_verbose ();
469 break;
470 case 'f':
471 overlap_func_level = 1;
472 break;
473 case 'F':
474 overlap_use_fullname = 1;
475 break;
476 case 'o':
477 overlap_obj_level = 1;
478 break;
479 case 'h':
480 overlap_hot_only = 1;
481 break;
482 case 't':
483 overlap_hot_threshold = atof (optarg);
484 break;
485 default:
486 overlap_usage ();
487 }
488 }
489
490 if (argc - optind == 2)
491 ret = profile_overlap (argv[optind], argv[optind+1]);
492 else
493 overlap_usage ();
494
495 return ret;
496}
497
498
c77556a5
RX
499/* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
500 otherwise the output of --help. */
501
502static void
503print_usage (int error_p)
504{
505 FILE *file = error_p ? stderr : stdout;
506 int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE;
507
508 fnotice (file, "Usage: %s [OPTION]... SUB_COMMAND [OPTION]...\n\n", progname);
509 fnotice (file, "Offline tool to handle gcda counts\n\n");
510 fnotice (file, " -h, --help Print this help, then exit\n");
511 fnotice (file, " -v, --version Print version number, then exit\n");
512 print_merge_usage_message (error_p);
513 print_rewrite_usage_message (error_p);
9b84e7a8 514 print_overlap_usage_message (error_p);
c77556a5
RX
515 fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
516 bug_report_url);
517 exit (status);
518}
519
520/* Print version information and exit. */
521
522static void
523print_version (void)
524{
525 fnotice (stdout, "%s %s%s\n", progname, pkgversion_string, version_string);
21fa2a29 526 fnotice (stdout, "Copyright %s 2014-2016 Free Software Foundation, Inc.\n",
c77556a5
RX
527 _("(C)"));
528 fnotice (stdout,
529 _("This is free software; see the source for copying conditions.\n"
530 "There is NO warranty; not even for MERCHANTABILITY or \n"
531 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
532 exit (SUCCESS_EXIT_CODE);
533}
534
535static const struct option options[] =
536{
537 { "help", no_argument, NULL, 'h' },
538 { "version", no_argument, NULL, 'v' },
539 { 0, 0, 0, 0 }
540};
541
542/* Process args, return index to first non-arg. */
543
544static int
545process_args (int argc, char **argv)
546{
547 int opt;
548
549 while ((opt = getopt_long (argc, argv, "+hv", options, NULL)) != -1)
550 {
551 switch (opt)
552 {
553 case 'h':
554 print_usage (false);
555 /* Print_usage will exit. */
556 case 'v':
557 print_version ();
558 /* Print_version will exit. */
559 default:
560 print_usage (true);
561 /* Print_usage will exit. */
562 }
563 }
564
565 return optind;
566}
567
568/* Main function for gcov-tool. */
569
570int
571main (int argc, char **argv)
572{
573 const char *p;
574 const char *sub_command;
575
576 p = argv[0] + strlen (argv[0]);
577 while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1]))
578 --p;
579 progname = p;
580
581 xmalloc_set_program_name (progname);
582
583 /* Unlock the stdio streams. */
584 unlock_std_streams ();
585
586 gcc_init_libintl ();
587
588 diagnostic_initialize (global_dc, 0);
589
590 /* Handle response files. */
591 expandargv (&argc, &argv);
592
593 process_args (argc, argv);
594 if (optind >= argc)
595 print_usage (true);
596
597 sub_command = argv[optind];
598
599 if (!strcmp (sub_command, "merge"))
600 return do_merge (argc - optind, argv + optind);
601 else if (!strcmp (sub_command, "rewrite"))
602 return do_rewrite (argc - optind, argv + optind);
9b84e7a8
RX
603 else if (!strcmp (sub_command, "overlap"))
604 return do_overlap (argc - optind, argv + optind);
c77556a5
RX
605
606 print_usage (true);
607}