diff options
author | Rong Xu <xur@google.com> | 2014-07-11 05:48:07 +0000 |
---|---|---|
committer | Rong Xu <xur@gcc.gnu.org> | 2014-07-11 05:48:07 +0000 |
commit | c77556a5d1e225024a4f9dafe5a1a6c316a86b83 (patch) | |
tree | 99edf70eadd9518774cdee53c167eb9d38580232 /gcc | |
parent | c14e64d4cac8f0b384e55aeff5e7074ce1bcc76d (diff) | |
download | gcc-c77556a5d1e225024a4f9dafe5a1a6c316a86b83.zip gcc-c77556a5d1e225024a4f9dafe5a1a6c316a86b83.tar.gz gcc-c77556a5d1e225024a4f9dafe5a1a6c316a86b83.tar.bz2 |
Add gcov-tool: an offline gcda profile processing tool Support.
2014-07-10 Rong Xu <xur@google.com>
Add gcov-tool: an offline gcda profile processing tool
Support.
* gcc/gcov-io.c (gcov_position): Make avaialble to gcov-tool.
(gcov_is_error): Ditto.
(gcov_read_string): Ditto.
(gcov_read_sync): Ditto.
* gcc/gcov-io.h: Move counter defines to gcov-counter.def.
* gcc/gcov-dump.c (tag_counters): Use gcov-counter.def.
* gcc/coverage.c: Ditto.
* gcc/gcov-tool.c: Offline gcda profile processing tool.
(unlink_gcda_file): Remove one gcda file.
(unlink_profile_dir): Remove gcda files from the profile path.
(gcov_output_files): Output gcda files to an output dir.
(profile_merge): Merge two profiles in directory.
(print_merge_usage_message): Print merge usage.
(merge_usage): Print merge usage and exit.
(do_merge): Driver for profile merge sub-command.
(profile_rewrite): Rewrite profile.
(print_rewrite_usage_message): Print rewrite usage.
(rewrite_usage): Print rewrite usage and exit.
(do_rewrite): Driver for profile rewrite sub-command.
(print_usage): Print gcov-info usage and exit.
(print_version): Print gcov-info version.
(process_args): Process arguments.
(main): Main routine for gcov-tool.
* gcc/Makefile.in: Build and install gcov-tool.
* gcc/gcov-counter.def: New file split from gcov-io.h.
* libgcc/libgcov-driver.c (gcov_max_filename): Make available
to gcov-tool.
* libgcc/libgcov-merge.c (__gcov_merge_add): Replace
gcov_read_counter() with a Macro.
(__gcov_merge_ior): Ditto.
(__gcov_merge_time_profile): Ditto.
(__gcov_merge_single): Ditto.
(__gcov_merge_delta): Ditto.
* libgcc/libgcov-util.c (void gcov_set_verbose): Set the verbose flag
in the utility functions.
(set_fn_ctrs): Utility function for reading gcda files to in-memory
gcov_list object link lists.
(tag_function): Ditto.
(tag_blocks): Ditto.
(tag_arcs): Ditto.
(tag_lines): Ditto.
(tag_counters): Ditto.
(tag_summary): Ditto.
(read_gcda_finalize): Ditto.
(read_gcda_file): Ditto.
(ftw_read_file): Ditto.
(read_profile_dir_init): Ditto.
(gcov_read_profile_dir): Ditto.
(gcov_read_counter_mem): Ditto.
(gcov_get_merge_weight): Ditto.
(merge_wrapper): A wrapper function that calls merging handler.
(gcov_merge): Merge two gcov_info objects with weights.
(find_match_gcov_info): Find the matched gcov_info in the list.
(gcov_profile_merge): Merge two gcov_info object lists.
(__gcov_add_counter_op): Process edge profile counter values.
(__gcov_ior_counter_op): Process IOR profile counter values.
(__gcov_delta_counter_op): Process delta profile counter values.
(__gcov_single_counter_op): Process single profile counter values.
(fp_scale): Callback function for float-point scaling.
(int_scale): Callback function for integer fraction scaling.
(gcov_profile_scale): Scaling profile counters.
(gcov_profile_normalize): Normalize profile counters.
* libgcc/libgcov.h: Add headers and functions for gcov-tool use.
(gcov_get_counter): New.
(gcov_get_counter_target): Ditto.
(struct gcov_info): Make the functions field mutable in gcov-tool
compilation.
* gcc/doc/gcc.texi: Include gcov-tool.texi.
* gcc/doc/gcov-tool.texi: Document for gcov-tool.
From-SVN: r212448
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 32 | ||||
-rw-r--r-- | gcc/Makefile.in | 46 | ||||
-rw-r--r-- | gcc/coverage.c | 15 | ||||
-rw-r--r-- | gcc/doc/gcc.texi | 3 | ||||
-rw-r--r-- | gcc/doc/gcov-tool.texi | 189 | ||||
-rw-r--r-- | gcc/gcov-counter.def | 54 | ||||
-rw-r--r-- | gcc/gcov-dump.c | 6 | ||||
-rw-r--r-- | gcc/gcov-io.c | 20 | ||||
-rw-r--r-- | gcc/gcov-io.h | 57 | ||||
-rw-r--r-- | gcc/gcov-tool.c | 478 |
10 files changed, 849 insertions, 51 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a7dcc02..771a887 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,35 @@ +2014-07-10 Rong Xu <xur@google.com> + + Add gcov-tool: an offline gcda profile processing tool + Support. + * gcov-io.c (gcov_position): Make avaialble to gcov-tool. + (gcov_is_error): Ditto. + (gcov_read_string): Ditto. + (gcov_read_sync): Ditto. + * gcov-io.h: Move counter defines to gcov-counter.def. + * gcov-dump.c (tag_counters): Use gcov-counter.def. + * coverage.c: Ditto. + * gcov-tool.c: Offline gcda profile processing tool. + (unlink_gcda_file): Remove one gcda file. + (unlink_profile_dir): Remove gcda files from the profile path. + (gcov_output_files): Output gcda files to an output dir. + (profile_merge): Merge two profiles in directory. + (print_merge_usage_message): Print merge usage. + (merge_usage): Print merge usage and exit. + (do_merge): Driver for profile merge sub-command. + (profile_rewrite): Rewrite profile. + (print_rewrite_usage_message): Print rewrite usage. + (rewrite_usage): Print rewrite usage and exit. + (do_rewrite): Driver for profile rewrite sub-command. + (print_usage): Print gcov-info usage and exit. + (print_version): Print gcov-info version. + (process_args): Process arguments. + (main): Main routine for gcov-tool. + * Makefile.in: Build and install gcov-tool. + * gcov-counter.def: New file split from gcov-io.h. + * doc/gcc.texi: Include gcov-tool.texi. + * doc/gcov-tool.texi: Document for gcov-tool. + 2014-07-10 Richard Biener <rguenther@suse.de> PR tree-optimization/61757 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index af6554f..187e6b6 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -123,7 +123,8 @@ SUBDIRS =@subdirs@ build # Selection of languages to be made. CONFIG_LANGUAGES = @all_selected_languages@ -LANGUAGES = c gcov$(exeext) gcov-dump$(exeext) $(CONFIG_LANGUAGES) +LANGUAGES = c gcov$(exeext) gcov-dump$(exeext) gcov-tool$(exeext) \ + $(CONFIG_LANGUAGES) # Default values for variables overridden in Makefile fragments. # CFLAGS is for the user to override to, e.g., do a cross build with -O2. @@ -196,6 +197,9 @@ GCC_WARN_CXXFLAGS = $(LOOSE_WARN) $($(@D)-warn) $(NOCOMMON_FLAG) $($@-warn) # flex output may yield harmless "no previous prototype" warnings build/gengtype-lex.o-warn = -Wno-error gengtype-lex.o-warn = -Wno-error +libgcov-util.o-warn = -Wno-error +libgcov-driver-tool.o-warn = -Wno-error +libgcov-merge-tool.o-warn = -Wno-error # All warnings have to be shut off in stage1 if the compiler used then # isn't gcc; configure determines that. WARN_CFLAGS will be either @@ -769,6 +773,7 @@ GCC_INSTALL_NAME := $(shell echo gcc|sed '$(program_transform_name)') GCC_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gcc|sed '$(program_transform_name)') CPP_INSTALL_NAME := $(shell echo cpp|sed '$(program_transform_name)') GCOV_INSTALL_NAME := $(shell echo gcov|sed '$(program_transform_name)') +GCOV_TOOL_INSTALL_NAME := $(shell echo gcov-tool|sed '$(program_transform_name)') # Setup the testing framework, if you have one EXPECT = `if [ -f $${rootme}/../expect/expect ] ; then \ @@ -890,7 +895,7 @@ BASIC_BLOCK_H = basic-block.h $(PREDICT_H) $(VEC_H) $(FUNCTION_H) \ GIMPLE_H = gimple.h gimple.def gsstruct.def pointer-set.h $(VEC_H) \ $(GGC_H) $(BASIC_BLOCK_H) $(TREE_H) tree-ssa-operands.h \ tree-ssa-alias.h $(INTERNAL_FN_H) $(HASH_TABLE_H) is-a.h -GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h +GCOV_IO_H = gcov-io.h gcov-iov.h auto-host.h gcov-counter.def RECOG_H = recog.h EMIT_RTL_H = emit-rtl.h FLAGS_H = flags.h flag-types.h $(OPTIONS_H) @@ -1492,7 +1497,7 @@ ALL_HOST_FRONTEND_OBJS = $(foreach v,$(CONFIG_LANGUAGES),$($(v)_OBJS)) ALL_HOST_BACKEND_OBJS = $(GCC_OBJS) $(OBJS) $(OBJS-libcommon) \ $(OBJS-libcommon-target) @TREEBROWSER@ main.o c-family/cppspec.o \ $(COLLECT2_OBJS) $(EXTRA_GCC_OBJS) $(GCOV_OBJS) $(GCOV_DUMP_OBJS) \ - lto-wrapper.o collect-utils.o + $(GCOV_TOOL_OBJS) lto-wrapper.o collect-utils.o # This lists all host object files, whether they are included in this # compilation or not. @@ -1517,6 +1522,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \ $(SPECS) collect2$(exeext) gcc-ar$(exeext) gcc-nm$(exeext) \ gcc-ranlib$(exeext) \ gcov-iov$(build_exeext) gcov$(exeext) gcov-dump$(exeext) \ + gcov-tool$(exeect) \ gengtype$(exeext) *.[0-9][0-9].* *.[si] *-checksum.c libbackend.a \ libcommon-target.a libcommon.a libgcc.mk @@ -2576,6 +2582,22 @@ GCOV_DUMP_OBJS = gcov-dump.o gcov-dump$(exeext): $(GCOV_DUMP_OBJS) $(LIBDEPS) +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) $(GCOV_DUMP_OBJS) \ $(LIBS) -o $@ + +GCOV_TOOL_DEP_FILES = $(srcdir)/../libgcc/libgcov-util.c gcov-io.c $(GCOV_IO_H) \ + $(srcdir)/../libgcc/libgcov-driver.c $(srcdir)/../libgcc/libgcov-driver-system.c \ + $(srcdir)/../libgcc/libgcov-merge.c \ + $(SYSTEM_H) coretypes.h $(TM_H) $(CONFIG_H) version.h intl.h $(DIAGNOSTIC_H) +libgcov-util.o: $(srcdir)/../libgcc/libgcov-util.c $(GCOV_TOOL_DEP_FILES) + +$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) -o $@ $< +libgcov-driver-tool.o: $(srcdir)/../libgcc/libgcov-driver.c $(GCOV_TOOL_DEP_FILES) + +$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + -DIN_GCOV_TOOL=1 -o $@ $< +libgcov-merge-tool.o: $(srcdir)/../libgcc/libgcov-merge.c $(GCOV_TOOL_DEP_FILES) + +$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + -DIN_GCOV_TOOL=1 -o $@ $< +GCOV_TOOL_OBJS = gcov-tool.o libgcov-util.o libgcov-driver-tool.o libgcov-merge-tool.o +gcov-tool$(exeext): $(GCOV_TOOL_OBJS) $(LIBDEPS) + +$(LINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) $(GCOV_TOOL_OBJS) $(LIBS) -o $@ # # Build the include directories. The stamp files are stmp-* rather than # s-* so that mostlyclean does not force the include directory to @@ -2804,7 +2826,8 @@ TEXI_GCC_FILES = gcc.texi gcc-common.texi gcc-vers.texi frontends.texi \ contribute.texi compat.texi funding.texi gnu.texi gpl_v3.texi \ fdl.texi contrib.texi cppenv.texi cppopts.texi avr-mmcu.texi \ implement-c.texi implement-cxx.texi arm-neon-intrinsics.texi \ - arm-acle-intrinsics.texi aarch64-acle-intrinsics.texi + arm-acle-intrinsics.texi aarch64-acle-intrinsics.texi \ + gcov-tool.texi # we explicitly use $(srcdir)/doc/tm.texi here to avoid confusion with # the generated tm.texi; the latter might have a more recent timestamp, @@ -2925,7 +2948,8 @@ $(build_htmldir)/gccinstall/index.html: $(TEXI_GCCINSTALL_FILES) DESTDIR=$(@D) \ $(SHELL) $(srcdir)/doc/install.texi2html -MANFILES = doc/gcov.1 doc/cpp.1 doc/gcc.1 doc/gfdl.7 doc/gpl.7 doc/fsf-funding.7 +MANFILES = doc/gcov.1 doc/cpp.1 doc/gcc.1 doc/gfdl.7 doc/gpl.7 \ + doc/fsf-funding.7 doc/gcov-tool.1 generated-manpages: man @@ -3212,6 +3236,13 @@ install-common: native lang.install-common installdirs rm -f $(DESTDIR)$(bindir)/$(GCOV_INSTALL_NAME)$(exeext); \ $(INSTALL_PROGRAM) gcov$(exeext) $(DESTDIR)$(bindir)/$(GCOV_INSTALL_NAME)$(exeext); \ fi +# Install gcov-tool if it was compiled. + -if [ -f gcov-tool$(exeext) ]; \ + then \ + rm -f $(DESTDIR)$(bindir)/$(GCOV_TOOL_INSTALL_NAME)$(exeext); \ + $(INSTALL_PROGRAM) \ + gcov-tool$(exeext) $(DESTDIR)$(bindir)/$(GCOV_TOOL_INSTALL_NAME)$(exeext); \ + fi # Install the driver program as $(target_noncanonical)-gcc, # $(target_noncanonical)-gcc-$(version), and also as gcc if native. @@ -3317,6 +3348,11 @@ $(DESTDIR)$(man1dir)/$(GCOV_INSTALL_NAME)$(man1ext): doc/gcov.1 installdirs -$(INSTALL_DATA) $< $@ -chmod a-x $@ +$(DESTDIR)$(man1dir)/$(GCOV_TOOL_INSTALL_NAME)$(man1ext): doc/gcov-tool.1 installdirs + -rm -f $@ + -$(INSTALL_DATA) $< $@ + -chmod a-x $@ + # Install all the header files built in the include subdirectory. install-headers: $(INSTALL_HEADERS_DIR) # Fix symlinks to absolute paths in the installed include directory to diff --git a/gcc/coverage.c b/gcc/coverage.c index 0eeaaa5..1e47dd8 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -120,8 +120,19 @@ static unsigned bbg_file_stamp; static char *da_file_name; /* The names of merge functions for counters. */ -static const char *const ctr_merge_functions[GCOV_COUNTERS] = GCOV_MERGE_FUNCTIONS; -static const char *const ctr_names[GCOV_COUNTERS] = GCOV_COUNTER_NAMES; +#define STR(str) #str +#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) STR(__gcov_merge ## FN_TYPE), +static const char *const ctr_merge_functions[GCOV_COUNTERS] = { +#include "gcov-counter.def" +}; +#undef DEF_GCOV_COUNTER +#undef STR + +#define DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) NAME, +static const char *const ctr_names[GCOV_COUNTERS] = { +#include "gcov-counter.def" +}; +#undef DEF_GCOV_COUNTER /* Forward declarations. */ static void read_counts_file (void); diff --git a/gcc/doc/gcc.texi b/gcc/doc/gcc.texi index c1f3857..7ae2e75 100644 --- a/gcc/doc/gcc.texi +++ b/gcc/doc/gcc.texi @@ -66,6 +66,7 @@ Texts being (a) (see below), and with the Back-Cover Texts being (b) * gcc: (gcc). The GNU Compiler Collection. * g++: (gcc). The GNU C++ compiler. * gcov: (gcc) Gcov. @command{gcov}---a test coverage program. +* gcov-tool: (gcc) Gcov-tool. @command{gcov-tool}---an offline gcda profile processing program. @end direntry This file documents the use of the GNU compilers. @sp 1 @@ -138,6 +139,7 @@ Introduction, gccint, GNU Compiler Collection (GCC) Internals}. * Objective-C:: GNU Objective-C runtime features. * Compatibility:: Binary Compatibility * Gcov:: @command{gcov}---a test coverage program. +* Gcov-tool:: @command{gcov-tool}---an offline gcda profile processing program. * Trouble:: If you have trouble using GCC. * Bugs:: How, why and where to report bugs. * Service:: How To Get Help with GCC @@ -164,6 +166,7 @@ Introduction, gccint, GNU Compiler Collection (GCC) Internals}. @include objc.texi @include compat.texi @include gcov.texi +@include gcov-tool.texi @include trouble.texi @include bugreport.texi @include service.texi diff --git a/gcc/doc/gcov-tool.texi b/gcc/doc/gcov-tool.texi new file mode 100644 index 0000000..ff8b9e2 --- /dev/null +++ b/gcc/doc/gcov-tool.texi @@ -0,0 +1,189 @@ +@c Copyright (C) 2014 Free Software Foundation, Inc. +@c This is part of the GCC manual. +@c For copying conditions, see the file gcc.texi. + +@ignore +@c man begin COPYRIGHT +Copyright @copyright{} 2014 Free Software Foundation, Inc. + +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.3 or +any later version published by the Free Software Foundation; with the +Invariant Sections being ``GNU General Public License'' and ``Funding +Free Software'', the Front-Cover texts being (a) (see below), and with +the Back-Cover Texts being (b) (see below). A copy of the license is +included in the gfdl(7) man page. + +(a) The FSF's Front-Cover Text is: + + A GNU Manual + +(b) The FSF's Back-Cover Text is: + + You have freedom to copy and modify this GNU Manual, like GNU + software. Copies published by the Free Software Foundation raise + funds for GNU development. +@c man end +@c Set file name and title for the man page. +@setfilename gcov-tool +@settitle offline gcda profile processing tool +@end ignore + +@node Gcov-tool +@chapter @command{gcov-tool}---an Offline Gcda Profile Processing Tool + +@command{gcov-tool} is a tool you can use in conjunction with GCC to +manipulate or process gcda profile files offline. + +@menu +* Gcov-tool Intro:: Introduction to gcov-tool. +* Invoking Gcov-tool:: How to use gcov-tool. +@end menu + +@node Gcov-tool Intro +@section Introduction to @command{gcov-tool} +@c man begin DESCRIPTION + +@command{gcov-tool} is an offline tool to process gcc's gcda profile files. + +Current gcov-tool supports the following functionalities: + +@itemize @bullet +@item +merge two sets of profiles with weights. + +@item +read one set of profile and rewrite profile contents. One can scale or +normalize the count values. +@end itemize + +Examples of the use cases for this tool are: +@itemize @bullet +@item +Collect the profiles for different set of inputs, and use this tool to merge +them. One can specify the weight to factor in the relative importance of +each input. + +@item +Rewrite the profile after removing a subset of the gcda files, while maintaining +the consistency of the summary and the histogram. + +@item +It can also be used to debug or libgcov code as the tools shares the majority +code as the runtime library. +@end itemize + +Note that for the merging operation, this profile generated offline may +contain slight different values from the online merged profile. Here are +a list of typical differences: + +@itemize @bullet +@item +histogram difference: This offline tool recomputes the histogram after merging +the counters. The resulting histogram, therefore, is precise. The online +merging does not have this capability -- the histogram is merged from two +histograms and the result is an approximation. + +@item +summary checksum difference: Summary checksum uses a CRC32 operation. The value +depends on the link list order of gcov-info objects. This order is different in +gcov-tool from that in the online merge. It's expected to have different +summary checksums. It does not really matter as the compiler does not use this +checksum anywhere. + +@item +value profile counter values difference: Some counter values for value profile +are runtime dependent, like heap addresses. It's normal to see some difference +in these kind of counters. +@end itemize + +@c man end + +@node Invoking Gcov-tool +@section Invoking @command{gcov-tool} + +@smallexample +gcov-tool @r{[}@var{global-options}@r{]} SUB_COMMAND +@r{[}@var{sub_command-options}@r{]} @var{profile_dir} +@end smallexample + +@command{gcov-tool} accepts the following options: + +@ignore +@c man begin SYNOPSIS +gcov-tool [@option{-v}|@option{--version}] [@option{-h}|@option{--help}] + +gcov-tool merge [merge-options] @var{directory1} @var{directory2} + [@option{-v}|@option{--verbose}] + [@option{-o}|@option{ --output} @var{directory}] + [@option{-w}|@option{--weight} @var{w1,w2}] + +gcov-tool rewrite [rewrite-options] @var{directory} + [@option{-v}|@option{--verbose}] + [@option{-o}|@option{--output} @var{directory}] + [@option{-s}|@option{--scale} @var{float_or_simple-frac_value}] + [@option{-n}|@option{--normalize} @var{long_long_value}] +@c man end +@c man begin SEEALSO +gpl(7), gfdl(7), fsf-funding(7), gcc(1), gcov(1) and the Info entry for +@file{gcc}. +@c man end +@end ignore + +@c man begin OPTIONS +@table @gcctabopt +@item -h +@itemx --help +Display help about using @command{gcov-tool} (on the standard output), and +exit without doing any further processing. + +@item -v +@itemx --version +Display the @command{gcov-tool} version number (on the standard output), +and exit without doing any further processing. + +@item merge +Merge two profile directories. + +@table @gcctabopt +@item -v +@itemx --verbose +Set the verbose mode. + +@item -o @var{directory} +@itemx --output @var{directory} +Set the output profile directory. Default output directory name is +@var{merged_profile}. + +@item -w @var{w1},@var{w2} +@itemx --weight @var{w1},@var{w2} +Set the merge weights of the @var{directory1} and @var{directory2}, +respectively. The default weights are 1 for both. +@end table + +@item rewrite +Read the specified profile directory and rewrite to a new directory. + +@table @gcctabopt +@item -v +@itemx --verbose +Set the verbose mode. + +@item -o @var{directory} +@itemx --output @var{directory} +Set the output profile directory. Default output name is @var{rewrite_profile}. + +@item -s @var{float_or_simple-frac_value} +@itemx --scale @var{float_or_simple-frac_value} +Scale the profile counters. The specified value can be in floating point value, +or simple fraction value form, such 1, 2, 2/3, and 5/3. + +@item -n @var{long_long_value} +@itemx --normalize <long_long_value> +Normalize the profile. The specified value is the max counter value +in the new profile. + +@end table +@end table + +@c man end diff --git a/gcc/gcov-counter.def b/gcc/gcov-counter.def new file mode 100644 index 0000000..77affd4 --- /dev/null +++ b/gcc/gcov-counter.def @@ -0,0 +1,54 @@ +/* Definitions for the gcov counters in the GNU compiler. + Copyright (C) 2001-2014 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +/* Before including this file, define a macro: + + DEF_GCOV_COUNTER(COUNTER, NAME, FN_TYPE) + + This macro will be expanded to all supported gcov counters, their + names, or the type of handler functions. FN_TYPE will be + expanded to a handler function, like in gcov_merge, it is + expanded to __gcov_merge ## FN_TYPE. */ + +/* Arc transitions. */ +DEF_GCOV_COUNTER(GCOV_COUNTER_ARCS, "arcs", _add) + +/* Histogram of value inside an interval. */ +DEF_GCOV_COUNTER(GCOV_COUNTER_V_INTERVAL, "interval", _add) + +/* Histogram of exact power2 logarithm of a value. */ +DEF_GCOV_COUNTER(GCOV_COUNTER_V_POW2, "pow2", _add) + +/* The most common value of expression. */ +DEF_GCOV_COUNTER(GCOV_COUNTER_V_SINGLE, "single", _single) + +/* The most common difference between consecutive values of expression. */ +DEF_GCOV_COUNTER(GCOV_COUNTER_V_DELTA, "delta", _delta) + +/* The most common indirect address. */ +DEF_GCOV_COUNTER(GCOV_COUNTER_V_INDIR, "indirect_call", _single) + +/* Compute average value passed to the counter. */ +DEF_GCOV_COUNTER(GCOV_COUNTER_AVERAGE, "average", _add) + +/* IOR of the all values passed to counter. */ +DEF_GCOV_COUNTER(GCOV_COUNTER_IOR, "ior", _ior) + +/* Time profile collecting first run of a function */ +DEF_GCOV_COUNTER(GCOV_TIME_PROFILER, "time_profiler", _time_profile) diff --git a/gcc/gcov-dump.c b/gcc/gcov-dump.c index 22298ec..25e30cd 100644 --- a/gcc/gcov-dump.c +++ b/gcc/gcov-dump.c @@ -422,7 +422,11 @@ static void tag_counters (const char *filename ATTRIBUTE_UNUSED, unsigned tag ATTRIBUTE_UNUSED, unsigned length ATTRIBUTE_UNUSED) { - static const char *const counter_names[] = GCOV_COUNTER_NAMES; +#define DEF_GCOV_COUNTER(COUNTER, NAME, MERGE_FN) NAME, + static const char *const counter_names[] = { +#include "gcov-counter.def" +}; +#undef DEF_GCOV_COUNTER unsigned n_counts = GCOV_TAG_COUNTER_NUM (length); printf (" %s %u counts", diff --git a/gcc/gcov-io.c b/gcc/gcov-io.c index 547276f..c2cd170 100644 --- a/gcc/gcov-io.c +++ b/gcc/gcov-io.c @@ -64,7 +64,11 @@ GCOV_LINKAGE struct gcov_var } gcov_var; /* Save the current position in the gcov file. */ -static inline gcov_position_t +/* We need to expose this function when compiling for gcov-tool. */ +#ifndef IN_GCOV_TOOL +static inline +#endif +gcov_position_t gcov_position (void) { gcov_nonruntime_assert (gcov_var.mode > 0); @@ -72,7 +76,11 @@ gcov_position (void) } /* Return nonzero if the error flag is set. */ -static inline int +/* We need to expose this function when compiling for gcov-tool. */ +#ifndef IN_GCOV_TOOL +static inline +#endif +int gcov_is_error (void) { return gcov_var.file ? gcov_var.error : 1; @@ -557,11 +565,13 @@ gcov_read_counter (void) return value; } +/* We need to expose the below function when compiling for gcov-tool. */ + +#if !IN_LIBGCOV || defined (IN_GCOV_TOOL) /* Read string from coverage file. Returns a pointer to a static buffer, or NULL on empty string. You must copy the string before calling another gcov function. */ -#if !IN_LIBGCOV GCOV_LINKAGE const char * gcov_read_string (void) { @@ -642,7 +652,9 @@ gcov_read_summary (struct gcov_summary *summary) } } -#if !IN_LIBGCOV +/* We need to expose the below function when compiling for gcov-tool. */ + +#if !IN_LIBGCOV || defined (IN_GCOV_TOOL) /* Reset to a known position. BASE should have been obtained from gcov_position, LENGTH should be a record length. */ diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h index 58884dc..16e6c71 100644 --- a/gcc/gcov-io.h +++ b/gcc/gcov-io.h @@ -247,50 +247,29 @@ typedef uint64_t gcov_type_unsigned; /* Counters that are collected. */ -#define GCOV_COUNTER_ARCS 0 /* Arc transitions. */ -#define GCOV_COUNTERS_SUMMABLE 1 /* Counters which can be - summaried. */ -#define GCOV_FIRST_VALUE_COUNTER 1 /* The first of counters used for value - profiling. They must form a consecutive - interval and their order must match - the order of HIST_TYPEs in - value-prof.h. */ -#define GCOV_COUNTER_V_INTERVAL 1 /* Histogram of value inside an interval. */ -#define GCOV_COUNTER_V_POW2 2 /* Histogram of exact power2 logarithm - of a value. */ -#define GCOV_COUNTER_V_SINGLE 3 /* The most common value of expression. */ -#define GCOV_COUNTER_V_DELTA 4 /* The most common difference between - consecutive values of expression. */ - -#define GCOV_COUNTER_V_INDIR 5 /* The most common indirect address */ -#define GCOV_COUNTER_AVERAGE 6 /* Compute average value passed to the - counter. */ -#define GCOV_COUNTER_IOR 7 /* IOR of the all values passed to - counter. */ -#define GCOV_TIME_PROFILER 8 /* Time profile collecting first run of a function */ -#define GCOV_LAST_VALUE_COUNTER 8 /* The last of counters used for value - profiling. */ -#define GCOV_COUNTERS 9 + +#define DEF_GCOV_COUNTER(COUNTER, NAME, MERGE_FN) COUNTER, +enum { +#include "gcov-counter.def" +GCOV_COUNTERS +}; +#undef DEF_GCOV_COUNTER + +/* Counters which can be summaried. */ +#define GCOV_COUNTERS_SUMMABLE (GCOV_COUNTER_ARCS + 1) + +/* The first of counters used for value profiling. They must form a + consecutive interval and their order must match the order of + HIST_TYPEs in value-prof.h. */ +#define GCOV_FIRST_VALUE_COUNTER GCOV_COUNTERS_SUMMABLE + +/* The last of counters used for value profiling. */ +#define GCOV_LAST_VALUE_COUNTER (GCOV_COUNTERS - 1) /* Number of counters used for value profiling. */ #define GCOV_N_VALUE_COUNTERS \ (GCOV_LAST_VALUE_COUNTER - GCOV_FIRST_VALUE_COUNTER + 1) - /* A list of human readable names of the counters */ -#define GCOV_COUNTER_NAMES {"arcs", "interval", "pow2", "single", \ - "delta", "indirect_call", "average", "ior", "time_profiler"} - - /* Names of merge functions for counters. */ -#define GCOV_MERGE_FUNCTIONS {"__gcov_merge_add", \ - "__gcov_merge_add", \ - "__gcov_merge_add", \ - "__gcov_merge_single", \ - "__gcov_merge_delta", \ - "__gcov_merge_single", \ - "__gcov_merge_add", \ - "__gcov_merge_ior", \ - "__gcov_merge_time_profile" } - /* Convert a counter index to a tag. */ #define GCOV_TAG_FOR_COUNTER(COUNT) \ (GCOV_TAG_COUNTER_BASE + ((gcov_unsigned_t)(COUNT) << 17)) diff --git a/gcc/gcov-tool.c b/gcc/gcov-tool.c new file mode 100644 index 0000000..a83b797 --- /dev/null +++ b/gcc/gcov-tool.c @@ -0,0 +1,478 @@ +/* Gcc offline profile processing tool support. */ +/* Copyright (C) 2014 Free Software Foundation, Inc. + Contributed by Rong Xu <xur@google.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 3, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "intl.h" +#include "diagnostic.h" +#include "version.h" +#include "gcov-io.h" +#include <stdlib.h> +#include <stdio.h> +#include <sys/stat.h> +#include <unistd.h> +#include <ftw.h> +#include <getopt.h> + +extern int gcov_profile_merge (struct gcov_info*, struct gcov_info*, int, int); +extern int gcov_profile_normalize (struct gcov_info*, gcov_type); +extern int gcov_profile_scale (struct gcov_info*, float, int, int); +extern struct gcov_info* gcov_read_profile_dir (const char*, int); +extern void gcov_exit (void); +extern void set_gcov_list (struct gcov_info *); +extern void gcov_set_verbose (void); + +/* Set to verbose output mode. */ +static bool verbose; + +/* Remove file NAME if it has a gcda suffix. */ + +static int +unlink_gcda_file (const char *name, + const struct stat *status ATTRIBUTE_UNUSED, + int type ATTRIBUTE_UNUSED, + struct FTW *ftwbuf ATTRIBUTE_UNUSED) +{ + int ret = 0; + int len = strlen (name); + int len1 = strlen (GCOV_DATA_SUFFIX); + + if (len > len1 && !strncmp (len -len1 + name, GCOV_DATA_SUFFIX, len1)) + ret = remove (name); + + if (ret) + fatal_error ("error in removing %s\n", name); + + return ret; +} + +/* Remove the gcda files in PATH recursively. */ + +static int +unlink_profile_dir (const char *path) +{ + return nftw(path, unlink_gcda_file, 64, FTW_DEPTH | FTW_PHYS); +} + +/* Output GCOV_INFO lists PROFILE to directory OUT. Note that + we will remove all the gcda files in OUT. */ + +static void +gcov_output_files (const char *out, struct gcov_info *profile) +{ + char *pwd; + int ret; + + /* Try to make directory if it doesn't already exist. */ + if (access (out, F_OK) == -1) + { +#ifdef TARGET_POSIX_IO + if (mkdir (out, 0755) == -1 && errno != EEXIST) +#else + if (mkdir (out) == -1 && errno != EEXIST) +#endif + fatal_error ("Cannot make directory %s", out); + } else + unlink_profile_dir (out); + + /* Output new profile. */ + pwd = getcwd (NULL, 0); + + if (pwd == NULL) + fatal_error ("Cannot get current directory name"); + + ret = chdir (out); + if (ret) + fatal_error ("Cannot change directory to %s", out); + + set_gcov_list (profile); + gcov_exit (); + + ret = chdir (pwd); + if (ret) + fatal_error ("Cannot change directory to %s", pwd); + + free (pwd); +} + +/* Merging profile D1 and D2 with weight as W1 and W2, respectively. + The result profile is written to directory OUT. + Return 0 on success. */ + +static int +profile_merge (const char *d1, const char *d2, const char *out, int w1, int w2) +{ + struct gcov_info *d1_profile; + struct gcov_info *d2_profile; + int ret; + + d1_profile = gcov_read_profile_dir (d1, 0); + if (!d1_profile) + return 1; + + if (d2) + { + d2_profile = gcov_read_profile_dir (d2, 0); + if (!d2_profile) + return 1; + + /* The actual merge: we overwrite to d1_profile. */ + ret = gcov_profile_merge (d1_profile, d2_profile, w1, w2); + + if (ret) + return ret; + } + + gcov_output_files (out, d1_profile); + + return 0; +} + +/* Usage message for profile merge. */ + +static void +print_merge_usage_message (int error_p) +{ + FILE *file = error_p ? stderr : stdout; + + fnotice (file, " merge [options] <dir1> <dir2> Merge coverage file contents\n"); + fnotice (file, " -v, --verbose Verbose mode\n"); + fnotice (file, " -o, --output <dir> Output directory\n"); + fnotice (file, " -w, --weight <w1,w2> Set weights (float point values)\n"); +} + +static const struct option merge_options[] = +{ + { "verbose", no_argument, NULL, 'v' }, + { "output", required_argument, NULL, 'o' }, + { "weight", required_argument, NULL, 'w' }, + { 0, 0, 0, 0 } +}; + +/* Print merge usage and exit. */ + +static void +merge_usage (void) +{ + fnotice (stderr, "Merge subcomand usage:"); + print_merge_usage_message (true); + exit (FATAL_EXIT_CODE); +} + +/* Driver for profile merge sub-command. */ + +static int +do_merge (int argc, char **argv) +{ + int opt; + int ret; + const char *output_dir = 0; + int w1 = 1, w2 = 1; + + optind = 0; + while ((opt = getopt_long (argc, argv, "vo:w:", merge_options, NULL)) != -1) + { + switch (opt) + { + case 'v': + verbose = true; + gcov_set_verbose (); + break; + case 'o': + output_dir = optarg; + break; + case 'w': + sscanf (optarg, "%d,%d", &w1, &w2); + if (w1 < 0 || w2 < 0) + fatal_error ("weights need to be non-negative\n"); + break; + default: + merge_usage (); + } + } + + if (output_dir == NULL) + output_dir = "merged_profile"; + + if (argc - optind == 2) + ret = profile_merge (argv[optind], argv[optind+1], output_dir, w1, w2); + else + merge_usage (); + + return ret; +} + +/* If N_VAL is no-zero, normalize the profile by setting the largest counter + counter value to N_VAL and scale others counters proportionally. + Otherwise, multiply the all counters by SCALE. */ + +static int +profile_rewrite (const char *d1, const char *out, long long n_val, + float scale, int n, int d) +{ + struct gcov_info * d1_profile; + + d1_profile = gcov_read_profile_dir (d1, 0); + if (!d1_profile) + return 1; + + if (n_val) + gcov_profile_normalize (d1_profile, (gcov_type) n_val); + else + gcov_profile_scale (d1_profile, scale, n, d); + + gcov_output_files (out, d1_profile); + return 0; +} + +/* Usage function for profile rewrite. */ + +static void +print_rewrite_usage_message (int error_p) +{ + FILE *file = error_p ? stderr : stdout; + + fnotice (file, " rewrite [options] <dir> Rewrite coverage file contents\n"); + fnotice (file, " -v, --verbose Verbose mode\n"); + fnotice (file, " -o, --output <dir> Output directory\n"); + fnotice (file, " -s, --scale <float or simple-frac> Scale the profile counters\n"); + fnotice (file, " -n, --normalize <long long> Normalize the profile\n"); +} + +static const struct option rewrite_options[] = +{ + { "verbose", no_argument, NULL, 'v' }, + { "output", required_argument, NULL, 'o' }, + { "scale", required_argument, NULL, 's' }, + { "normalize", required_argument, NULL, 'n' }, + { 0, 0, 0, 0 } +}; + +/* Print profile rewrite usage and exit. */ + +static void +rewrite_usage (void) +{ + fnotice (stderr, "Rewrite subcommand usage:"); + print_rewrite_usage_message (true); + exit (FATAL_EXIT_CODE); +} + +/* Driver for profile rewrite sub-command. */ + +static int +do_rewrite (int argc, char **argv) +{ + int opt; + int ret; + const char *output_dir = 0; + long long normalize_val = 0; + float scale = 0.0; + int numerator = 1; + int denominator = 1; + int do_scaling = 0; + + optind = 0; + while ((opt = getopt_long (argc, argv, "vo:s:n:", rewrite_options, NULL)) != -1) + { + switch (opt) + { + case 'v': + verbose = true; + gcov_set_verbose (); + break; + case 'o': + output_dir = optarg; + break; + case 'n': + if (!do_scaling) + normalize_val = atoll (optarg); + else + fnotice (stderr, "scaling cannot co-exist with normalization," + " skipping\n"); + break; + case 's': + ret = 0; + do_scaling = 1; + if (strstr (optarg, "/")) + { + ret = sscanf (optarg, "%d/%d", &numerator, &denominator); + if (ret == 2) + { + if (numerator < 0 || denominator <= 0) + { + fnotice (stderr, "incorrect format in scaling, using 1/1\n"); + denominator = 1; + numerator = 1; + } + } + } + if (ret != 2) + { + ret = sscanf (optarg, "%f", &scale); + if (ret != 1) + fnotice (stderr, "incorrect format in scaling, using 1/1\n"); + else + denominator = 0; + } + + if (scale < 0.0) + fatal_error ("scale needs to be non-negative\n"); + + if (normalize_val != 0) + { + fnotice (stderr, "normalization cannot co-exist with scaling\n"); + normalize_val = 0; + } + break; + default: + rewrite_usage (); + } + } + + if (output_dir == NULL) + output_dir = "rewrite_profile"; + + if (argc - optind == 1) + { + if (denominator > 0) + ret = profile_rewrite (argv[optind], output_dir, 0, 0.0, numerator, denominator); + else + ret = profile_rewrite (argv[optind], output_dir, normalize_val, scale, 0, 0); + } + else + rewrite_usage (); + + return ret; +} + +/* Print a usage message and exit. If ERROR_P is nonzero, this is an error, + otherwise the output of --help. */ + +static void +print_usage (int error_p) +{ + FILE *file = error_p ? stderr : stdout; + int status = error_p ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; + + fnotice (file, "Usage: %s [OPTION]... SUB_COMMAND [OPTION]...\n\n", progname); + fnotice (file, "Offline tool to handle gcda counts\n\n"); + fnotice (file, " -h, --help Print this help, then exit\n"); + fnotice (file, " -v, --version Print version number, then exit\n"); + print_merge_usage_message (error_p); + print_rewrite_usage_message (error_p); + fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n", + bug_report_url); + exit (status); +} + +/* Print version information and exit. */ + +static void +print_version (void) +{ + fnotice (stdout, "%s %s%s\n", progname, pkgversion_string, version_string); + fnotice (stdout, "Copyright %s 2014 Free Software Foundation, Inc.\n", + _("(C)")); + fnotice (stdout, + _("This is free software; see the source for copying conditions.\n" + "There is NO warranty; not even for MERCHANTABILITY or \n" + "FITNESS FOR A PARTICULAR PURPOSE.\n\n")); + exit (SUCCESS_EXIT_CODE); +} + +static const struct option options[] = +{ + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { 0, 0, 0, 0 } +}; + +/* Process args, return index to first non-arg. */ + +static int +process_args (int argc, char **argv) +{ + int opt; + + while ((opt = getopt_long (argc, argv, "+hv", options, NULL)) != -1) + { + switch (opt) + { + case 'h': + print_usage (false); + /* Print_usage will exit. */ + case 'v': + print_version (); + /* Print_version will exit. */ + default: + print_usage (true); + /* Print_usage will exit. */ + } + } + + return optind; +} + +/* Main function for gcov-tool. */ + +int +main (int argc, char **argv) +{ + const char *p; + const char *sub_command; + + p = argv[0] + strlen (argv[0]); + while (p != argv[0] && !IS_DIR_SEPARATOR (p[-1])) + --p; + progname = p; + + xmalloc_set_program_name (progname); + + /* Unlock the stdio streams. */ + unlock_std_streams (); + + gcc_init_libintl (); + + diagnostic_initialize (global_dc, 0); + + /* Handle response files. */ + expandargv (&argc, &argv); + + process_args (argc, argv); + if (optind >= argc) + print_usage (true); + + sub_command = argv[optind]; + + if (!strcmp (sub_command, "merge")) + return do_merge (argc - optind, argv + optind); + else if (!strcmp (sub_command, "rewrite")) + return do_rewrite (argc - optind, argv + optind); + + print_usage (true); +} |