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_do_dump (struct gcov_info
*, int);
46 extern void gcov_set_verbose (void);
48 /* Set to verbose output mode. */
51 /* Remove file NAME if it has a gcda suffix. */
54 unlink_gcda_file (const char *name
,
55 const struct stat
*status ATTRIBUTE_UNUSED
,
56 int type ATTRIBUTE_UNUSED
,
57 struct FTW
*ftwbuf ATTRIBUTE_UNUSED
)
60 int len
= strlen (name
);
61 int len1
= strlen (GCOV_DATA_SUFFIX
);
63 if (len
> len1
&& !strncmp (len
-len1
+ name
, GCOV_DATA_SUFFIX
, len1
))
67 fatal_error ("error in removing %s\n", name
);
72 /* Remove the gcda files in PATH recursively. */
75 unlink_profile_dir (const char *path
)
77 return nftw(path
, unlink_gcda_file
, 64, FTW_DEPTH
| FTW_PHYS
);
80 /* Output GCOV_INFO lists PROFILE to directory OUT. Note that
81 we will remove all the gcda files in OUT. */
84 gcov_output_files (const char *out
, struct gcov_info
*profile
)
89 /* Try to make directory if it doesn't already exist. */
90 if (access (out
, F_OK
) == -1)
93 if (mkdir (out
, S_IRWXU
| S_IRWXG
| S_IRWXO
) == -1 && errno
!= EEXIST
)
95 if (mkdir (out
) == -1 && errno
!= EEXIST
)
97 fatal_error ("Cannot make directory %s", out
);
99 unlink_profile_dir (out
);
101 /* Output new profile. */
102 pwd
= getcwd (NULL
, 0);
105 fatal_error ("Cannot get current directory name");
109 fatal_error ("Cannot change directory to %s", out
);
111 gcov_do_dump (profile
, 0);
115 fatal_error ("Cannot change directory to %s", pwd
);
120 /* Merging profile D1 and D2 with weight as W1 and W2, respectively.
121 The result profile is written to directory OUT.
122 Return 0 on success. */
125 profile_merge (const char *d1
, const char *d2
, const char *out
, int w1
, int w2
)
127 struct gcov_info
*d1_profile
;
128 struct gcov_info
*d2_profile
;
131 d1_profile
= gcov_read_profile_dir (d1
, 0);
137 d2_profile
= gcov_read_profile_dir (d2
, 0);
141 /* The actual merge: we overwrite to d1_profile. */
142 ret
= gcov_profile_merge (d1_profile
, d2_profile
, w1
, w2
);
148 gcov_output_files (out
, d1_profile
);
153 /* Usage message for profile merge. */
156 print_merge_usage_message (int error_p
)
158 FILE *file
= error_p
? stderr
: stdout
;
160 fnotice (file
, " merge [options] <dir1> <dir2> Merge coverage file contents\n");
161 fnotice (file
, " -v, --verbose Verbose mode\n");
162 fnotice (file
, " -o, --output <dir> Output directory\n");
163 fnotice (file
, " -w, --weight <w1,w2> Set weights (float point values)\n");
166 static const struct option merge_options
[] =
168 { "verbose", no_argument
, NULL
, 'v' },
169 { "output", required_argument
, NULL
, 'o' },
170 { "weight", required_argument
, NULL
, 'w' },
174 /* Print merge usage and exit. */
179 fnotice (stderr
, "Merge subcomand usage:");
180 print_merge_usage_message (true);
181 exit (FATAL_EXIT_CODE
);
184 /* Driver for profile merge sub-command. */
187 do_merge (int argc
, char **argv
)
191 const char *output_dir
= 0;
195 while ((opt
= getopt_long (argc
, argv
, "vo:w:", merge_options
, NULL
)) != -1)
207 sscanf (optarg
, "%d,%d", &w1
, &w2
);
208 if (w1
< 0 || w2
< 0)
209 fatal_error ("weights need to be non-negative\n");
216 if (output_dir
== NULL
)
217 output_dir
= "merged_profile";
219 if (argc
- optind
== 2)
220 ret
= profile_merge (argv
[optind
], argv
[optind
+1], output_dir
, w1
, w2
);
227 /* If N_VAL is no-zero, normalize the profile by setting the largest counter
228 counter value to N_VAL and scale others counters proportionally.
229 Otherwise, multiply the all counters by SCALE. */
232 profile_rewrite (const char *d1
, const char *out
, long long n_val
,
233 float scale
, int n
, int d
)
235 struct gcov_info
* d1_profile
;
237 d1_profile
= gcov_read_profile_dir (d1
, 0);
242 gcov_profile_normalize (d1_profile
, (gcov_type
) n_val
);
244 gcov_profile_scale (d1_profile
, scale
, n
, d
);
246 gcov_output_files (out
, d1_profile
);
250 /* Usage function for profile rewrite. */
253 print_rewrite_usage_message (int error_p
)
255 FILE *file
= error_p
? stderr
: stdout
;
257 fnotice (file
, " rewrite [options] <dir> Rewrite coverage file contents\n");
258 fnotice (file
, " -v, --verbose Verbose mode\n");
259 fnotice (file
, " -o, --output <dir> Output directory\n");
260 fnotice (file
, " -s, --scale <float or simple-frac> Scale the profile counters\n");
261 fnotice (file
, " -n, --normalize <long long> Normalize the profile\n");
264 static const struct option rewrite_options
[] =
266 { "verbose", no_argument
, NULL
, 'v' },
267 { "output", required_argument
, NULL
, 'o' },
268 { "scale", required_argument
, NULL
, 's' },
269 { "normalize", required_argument
, NULL
, 'n' },
273 /* Print profile rewrite usage and exit. */
278 fnotice (stderr
, "Rewrite subcommand usage:");
279 print_rewrite_usage_message (true);
280 exit (FATAL_EXIT_CODE
);
283 /* Driver for profile rewrite sub-command. */
286 do_rewrite (int argc
, char **argv
)
290 const char *output_dir
= 0;
291 long long normalize_val
= 0;
298 while ((opt
= getopt_long (argc
, argv
, "vo:s:n:", rewrite_options
, NULL
)) != -1)
311 normalize_val
= atoll (optarg
);
313 fnotice (stderr
, "scaling cannot co-exist with normalization,"
319 if (strstr (optarg
, "/"))
321 ret
= sscanf (optarg
, "%d/%d", &numerator
, &denominator
);
324 if (numerator
< 0 || denominator
<= 0)
326 fnotice (stderr
, "incorrect format in scaling, using 1/1\n");
334 ret
= sscanf (optarg
, "%f", &scale
);
336 fnotice (stderr
, "incorrect format in scaling, using 1/1\n");
342 fatal_error ("scale needs to be non-negative\n");
344 if (normalize_val
!= 0)
346 fnotice (stderr
, "normalization cannot co-exist with scaling\n");
355 if (output_dir
== NULL
)
356 output_dir
= "rewrite_profile";
358 if (argc
- optind
== 1)
361 ret
= profile_rewrite (argv
[optind
], output_dir
, 0, 0.0, numerator
, denominator
);
363 ret
= profile_rewrite (argv
[optind
], output_dir
, normalize_val
, scale
, 0, 0);
371 /* Print a usage message and exit. If ERROR_P is nonzero, this is an error,
372 otherwise the output of --help. */
375 print_usage (int error_p
)
377 FILE *file
= error_p
? stderr
: stdout
;
378 int status
= error_p
? FATAL_EXIT_CODE
: SUCCESS_EXIT_CODE
;
380 fnotice (file
, "Usage: %s [OPTION]... SUB_COMMAND [OPTION]...\n\n", progname
);
381 fnotice (file
, "Offline tool to handle gcda counts\n\n");
382 fnotice (file
, " -h, --help Print this help, then exit\n");
383 fnotice (file
, " -v, --version Print version number, then exit\n");
384 print_merge_usage_message (error_p
);
385 print_rewrite_usage_message (error_p
);
386 fnotice (file
, "\nFor bug reporting instructions, please see:\n%s.\n",
391 /* Print version information and exit. */
396 fnotice (stdout
, "%s %s%s\n", progname
, pkgversion_string
, version_string
);
397 fnotice (stdout
, "Copyright %s 2014 Free Software Foundation, Inc.\n",
400 _("This is free software; see the source for copying conditions.\n"
401 "There is NO warranty; not even for MERCHANTABILITY or \n"
402 "FITNESS FOR A PARTICULAR PURPOSE.\n\n"));
403 exit (SUCCESS_EXIT_CODE
);
406 static const struct option options
[] =
408 { "help", no_argument
, NULL
, 'h' },
409 { "version", no_argument
, NULL
, 'v' },
413 /* Process args, return index to first non-arg. */
416 process_args (int argc
, char **argv
)
420 while ((opt
= getopt_long (argc
, argv
, "+hv", options
, NULL
)) != -1)
426 /* Print_usage will exit. */
429 /* Print_version will exit. */
432 /* Print_usage will exit. */
439 /* Main function for gcov-tool. */
442 main (int argc
, char **argv
)
445 const char *sub_command
;
447 p
= argv
[0] + strlen (argv
[0]);
448 while (p
!= argv
[0] && !IS_DIR_SEPARATOR (p
[-1]))
452 xmalloc_set_program_name (progname
);
454 /* Unlock the stdio streams. */
455 unlock_std_streams ();
459 diagnostic_initialize (global_dc
, 0);
461 /* Handle response files. */
462 expandargv (&argc
, &argv
);
464 process_args (argc
, argv
);
468 sub_command
= argv
[optind
];
470 if (!strcmp (sub_command
, "merge"))
471 return do_merge (argc
- optind
, argv
+ optind
);
472 else if (!strcmp (sub_command
, "rewrite"))
473 return do_rewrite (argc
- optind
, argv
+ optind
);