]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/gcov-tool.c
fix PR68343: disable fuse-*.c tests for isl 0.14 or earlier
[thirdparty/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, 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
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 <long long> 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 #ifdef HAVE_LONG_LONG
295 long long normalize_val = 0;
296 #else
297 int64_t normalize_val = 0;
298 #endif
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)
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
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)
355 fatal_error (input_location, "scale needs to be non-negative\n");
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
384 /* Driver function to computer the overlap score b/w profile D1 and D2.
385 Return 1 on error and 0 if OK. */
386
387 static int
388 profile_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
411 static void
412 print_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
426 static 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
439 static void
440 overlap_usage (void)
441 {
442 fnotice (stderr, "Overlap subcomand usage:");
443 print_overlap_usage_message (true);
444 exit (FATAL_EXIT_CODE);
445 }
446
447 int overlap_func_level;
448 int overlap_obj_level;
449 int overlap_hot_only;
450 int overlap_use_fullname;
451 double overlap_hot_threshold = 0.005;
452
453 /* Driver for profile overlap sub-command. */
454
455 static int
456 do_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
499 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
500 otherwise the output of --help. */
501
502 static void
503 print_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);
514 print_overlap_usage_message (error_p);
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
522 static void
523 print_version (void)
524 {
525 fnotice (stdout, "%s %s%s\n", progname, pkgversion_string, version_string);
526 fnotice (stdout, "Copyright %s 2014-2016 Free Software Foundation, Inc.\n",
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
535 static 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
544 static int
545 process_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
570 int
571 main (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);
603 else if (!strcmp (sub_command, "overlap"))
604 return do_overlap (argc - optind, argv + optind);
605
606 print_usage (true);
607 }