]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/gcov-tool.c
1 /* Gcc offline profile processing tool support. */
2 /* Copyright (C) 2014 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
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
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/>. */
28 #include "coretypes.h"
31 #include "diagnostic.h"
41 extern int gcov_profile_merge (struct gcov_info
*, struct gcov_info
*, int, int);
42 extern int gcov_profile_normalize (struct gcov_info
*, gcov_type
);
43 extern int gcov_profile_scale (struct gcov_info
*, float, int, int);
44 extern struct gcov_info
* gcov_read_profile_dir (const char*, int);
45 extern void gcov_exit (void);
46 extern void set_gcov_list (struct gcov_info
*);
47 extern void gcov_set_verbose (void);
49 /* Set to verbose output mode. */
52 /* Remove file NAME if it has a gcda suffix. */
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
)
61 int len
= strlen (name
);
62 int len1
= strlen (GCOV_DATA_SUFFIX
);
64 if (len
> len1
&& !strncmp (len
-len1
+ name
, GCOV_DATA_SUFFIX
, len1
))
68 fatal_error ("error in removing %s\n", name
);
73 /* Remove the gcda files in PATH recursively. */
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. */
85 gcov_output_files (const char *out
, struct gcov_info
*profile
)
90 /* Try to make directory if it doesn't already exist. */
91 if (access (out
, F_OK
) == -1)
94 if (mkdir (out
, S_IRWXU
| S_IRWXG
| S_IRWXO
) == -1 && errno
!= EEXIST
)
96 if (mkdir (out
) == -1 && errno
!= EEXIST
)
98 fatal_error ("Cannot make directory %s", out
);
100 unlink_profile_dir (out
);
102 /* Output new profile. */
103 pwd
= getcwd (NULL
, 0);
106 fatal_error ("Cannot get current directory name");
110 fatal_error ("Cannot change directory to %s", out
);
112 set_gcov_list (profile
);
117 fatal_error ("Cannot change directory to %s", pwd
);
122 /* Merging profile D1 and D2 with weight as W1 and W2, respectively.
123 The result profile is written to directory OUT.
124 Return 0 on success. */
127 profile_merge (const char *d1
, const char *d2
, const char *out
, int w1
, int w2
)
129 struct gcov_info
*d1_profile
;
130 struct gcov_info
*d2_profile
;
133 d1_profile
= gcov_read_profile_dir (d1
, 0);
139 d2_profile
= gcov_read_profile_dir (d2
, 0);
143 /* The actual merge: we overwrite to d1_profile. */
144 ret
= gcov_profile_merge (d1_profile
, d2_profile
, w1
, w2
);
150 gcov_output_files (out
, d1_profile
);
155 /* Usage message for profile merge. */
158 print_merge_usage_message (int error_p
)
160 FILE *file
= error_p
? stderr
: stdout
;
162 fnotice (file
, " merge [options] <dir1> <dir2> Merge coverage file contents\n");
163 fnotice (file
, " -v, --verbose Verbose mode\n");
164 fnotice (file
, " -o, --output <dir> Output directory\n");
165 fnotice (file
, " -w, --weight <w1,w2> Set weights (float point values)\n");
168 static const struct option merge_options
[] =
170 { "verbose", no_argument
, NULL
, 'v' },
171 { "output", required_argument
, NULL
, 'o' },
172 { "weight", required_argument
, NULL
, 'w' },
176 /* Print merge usage and exit. */
181 fnotice (stderr
, "Merge subcomand usage:");
182 print_merge_usage_message (true);
183 exit (FATAL_EXIT_CODE
);
186 /* Driver for profile merge sub-command. */
189 do_merge (int argc
, char **argv
)
193 const char *output_dir
= 0;
197 while ((opt
= getopt_long (argc
, argv
, "vo:w:", merge_options
, NULL
)) != -1)
209 sscanf (optarg
, "%d,%d", &w1
, &w2
);
210 if (w1
< 0 || w2
< 0)
211 fatal_error ("weights need to be non-negative\n");
218 if (output_dir
== NULL
)
219 output_dir
= "merged_profile";
221 if (argc
- optind
== 2)
222 ret
= profile_merge (argv
[optind
], argv
[optind
+1], output_dir
, w1
, w2
);
229 /* If N_VAL is no-zero, normalize the profile by setting the largest counter
230 counter value to N_VAL and scale others counters proportionally.
231 Otherwise, multiply the all counters by SCALE. */
234 profile_rewrite (const char *d1
, const char *out
, long long n_val
,
235 float scale
, int n
, int d
)
237 struct gcov_info
* d1_profile
;
239 d1_profile
= gcov_read_profile_dir (d1
, 0);
244 gcov_profile_normalize (d1_profile
, (gcov_type
) n_val
);
246 gcov_profile_scale (d1_profile
, scale
, n
, d
);
248 gcov_output_files (out
, d1_profile
);
252 /* Usage function for profile rewrite. */
255 print_rewrite_usage_message (int error_p
)
257 FILE *file
= error_p
? stderr
: stdout
;
259 fnotice (file
, " rewrite [options] <dir> Rewrite coverage file contents\n");
260 fnotice (file
, " -v, --verbose Verbose mode\n");
261 fnotice (file
, " -o, --output <dir> Output directory\n");
262 fnotice (file
, " -s, --scale <float or simple-frac> Scale the profile counters\n");
263 fnotice (file
, " -n, --normalize <long long> Normalize the profile\n");
266 static const struct option rewrite_options
[] =
268 { "verbose", no_argument
, NULL
, 'v' },
269 { "output", required_argument
, NULL
, 'o' },
270 { "scale", required_argument
, NULL
, 's' },
271 { "normalize", required_argument
, NULL
, 'n' },
275 /* Print profile rewrite usage and exit. */
280 fnotice (stderr
, "Rewrite subcommand usage:");
281 print_rewrite_usage_message (true);
282 exit (FATAL_EXIT_CODE
);
285 /* Driver for profile rewrite sub-command. */
288 do_rewrite (int argc
, char **argv
)
292 const char *output_dir
= 0;
293 long long normalize_val
= 0;
300 while ((opt
= getopt_long (argc
, argv
, "vo:s:n:", rewrite_options
, NULL
)) != -1)
313 normalize_val
= atoll (optarg
);
315 fnotice (stderr
, "scaling cannot co-exist with normalization,"
321 if (strstr (optarg
, "/"))
323 ret
= sscanf (optarg
, "%d/%d", &numerator
, &denominator
);
326 if (numerator
< 0 || denominator
<= 0)
328 fnotice (stderr
, "incorrect format in scaling, using 1/1\n");
336 ret
= sscanf (optarg
, "%f", &scale
);
338 fnotice (stderr
, "incorrect format in scaling, using 1/1\n");
344 fatal_error ("scale needs to be non-negative\n");
346 if (normalize_val
!= 0)
348 fnotice (stderr
, "normalization cannot co-exist with scaling\n");
357 if (output_dir
== NULL
)
358 output_dir
= "rewrite_profile";
360 if (argc
- optind
== 1)
363 ret
= profile_rewrite (argv
[optind
], output_dir
, 0, 0.0, numerator
, denominator
);
365 ret
= profile_rewrite (argv
[optind
], output_dir
, normalize_val
, scale
, 0, 0);
373 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
374 otherwise the output of --help. */
377 print_usage (int error_p
)
379 FILE *file
= error_p
? stderr
: stdout
;
380 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
382 fnotice (file
, "Usage: %s [OPTION]... SUB_COMMAND [OPTION]...\n\n", progname
);
383 fnotice (file
, "Offline tool to handle gcda counts\n\n");
384 fnotice (file
, " -h, --help Print this help, then exit\n");
385 fnotice (file
, " -v, --version Print version number, then exit\n");
386 print_merge_usage_message (error_p
);
387 print_rewrite_usage_message (error_p
);
388 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
393 /* Print version information and exit. */
398 fnotice (stdout
, "%s %s%s\n", progname
, pkgversion_string
, version_string
);
399 fnotice (stdout
, "Copyright %s 2014 Free Software Foundation, Inc.\n",
402 _("This is free software; see the source for copying conditions.\n"
403 "There is NO warranty; not even for MERCHANTABILITY or \n"
404 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
405 exit (SUCCESS_EXIT_CODE
);
408 static const struct option options
[] =
410 { "help", no_argument
, NULL
, 'h' },
411 { "version", no_argument
, NULL
, 'v' },
415 /* Process args, return index to first non-arg. */
418 process_args (int argc
, char **argv
)
422 while ((opt
= getopt_long (argc
, argv
, "+hv", options
, NULL
)) != -1)
428 /* Print_usage will exit. */
431 /* Print_version will exit. */
434 /* Print_usage will exit. */
441 /* Main function for gcov-tool. */
444 main (int argc
, char **argv
)
447 const char *sub_command
;
449 p
= argv
[0] + strlen (argv
[0]);
450 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
454 xmalloc_set_program_name (progname
);
456 /* Unlock the stdio streams. */
457 unlock_std_streams ();
461 diagnostic_initialize (global_dc
, 0);
463 /* Handle response files. */
464 expandargv (&argc
, &argv
);
466 process_args (argc
, argv
);
470 sub_command
= argv
[optind
];
472 if (!strcmp (sub_command
, "merge"))
473 return do_merge (argc
- optind
, argv
+ optind
);
474 else if (!strcmp (sub_command
, "rewrite"))
475 return do_rewrite (argc
- optind
, argv
+ optind
);