This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [google] Add intermediate text format for gcov (issue4595053)


On Tue, Jun 14, 2011 at 8:14 AM, Sharad Singhai <singhai@google.com> wrote:
> This patch adds an intermediate gcov text format which does not require
> source code. This format can be used by lcov or other tools.
>
> I have bootstrapped it on x86 and all tests pass. Okay for main?

I think there should be either a specification of the format in gcov.texi
or a reference to a specification if it exists elsewhere.

Richard.

> Thanks,
> Sharad
>
> 2011-06-13 ? Sharad Singhai ?<singhai@google.com>
>
> ? ? ? ?Google Ref 39999
>
> ? ? ? ?* doc/gcov.texi: Document gcov intermediate format.
> ? ? ? ?* gcov.c (get_gcov_file_intermediate_name): New function.
> ? ? ? ?(output_intermediate_file): New function.
> ? ? ? ?* testsuite/g++.dg/gcov/gcov-7.C: New test.
>
>
> Index: doc/gcov.texi
> ===================================================================
> --- doc/gcov.texi ? ? ? (revision 174926)
> +++ doc/gcov.texi ? ? ? (working copy)
> @@ -130,6 +130,7 @@
> ? ? ?[@option{-f}|@option{--function-summaries}]
> ? ? ?[@option{-o}|@option{--object-directory} @var{directory|file}] @var{sourcefiles}
> ? ? ?[@option{-u}|@option{--unconditional-branches}]
> + ? ? [@option{-i}|@option{--intermediate-format}]
> ? ? ?[@option{-d}|@option{--display-progress}]
> ?@c man end
> ?@c man begin SEEALSO
> @@ -216,6 +217,12 @@
> ?@itemx --display-progress
> ?Display the progress on the standard output.
>
> +@item -i
> +@itemx --intermediate-format
> +Output gcov file in an intermediate text format that can be used by
> +@command{lcov} or other applications. It will output a single *.gcov file per
> +*gcda file. No source code is required.
> +
> ?@end table
>
> ?@command{gcov} should be run with the current directory the same as that
> Index: gcov.c
> ===================================================================
> --- gcov.c ? ? ?(revision 174926)
> +++ gcov.c ? ? ?(working copy)
> @@ -38,6 +38,7 @@
> ?#include "tm.h"
> ?#include "intl.h"
> ?#include "version.h"
> +#include "demangle.h"
>
> ?#include <getopt.h>
>
> @@ -310,6 +311,9 @@
>
> ?static int flag_display_progress = 0;
>
> +/* Output *.gcov file in intermediate format used by 'lcov'. ?*/
> +static int flag_intermediate_format = 0;
> +
> ?/* For included files, make the gcov output file name include the name
> ? ?of the input source file. ?For example, if x.h is included in a.c,
> ? ?then the output file name is a.c##x.h.gcov instead of x.h.gcov. ?*/
> @@ -436,6 +440,11 @@
> ? fnotice (file, " ?-o, --object-directory DIR|FILE Search for object files in DIR or called FILE\n");
> ? fnotice (file, " ?-p, --preserve-paths ? ? ? ? ? ?Preserve all pathname components\n");
> ? fnotice (file, " ?-u, --unconditional-branches ? ?Show unconditional branch counts too\n");
> + ?fnotice (file, " ?-i, --intermediate-format ? ? ? Output .gcov file in an intermediate text\n\
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?format that can be used by 'lcov' or other\n\
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?applications. ?It will output a single\n\
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?.gcov file per .gcda file. ?No source file\n\
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?is required.\n");
> ? fnotice (file, " ?-d, --display-progress ? ? ? ? ?Display progress information\n");
> ? fnotice (file, "\nFor bug reporting instructions, please see:\n%s.\n",
> ? ? ? ? ? bug_report_url);
> @@ -472,6 +481,7 @@
> ? { "object-file", ? ? ? ? ?required_argument, NULL, 'o' },
> ? { "unconditional-branches", no_argument, ? ? NULL, 'u' },
> ? { "display-progress", ? ? no_argument, ? ? ? NULL, 'd' },
> + ?{ "intermediate-format", ?no_argument, ? ? ? NULL, 'i' },
> ? { 0, 0, 0, 0 }
> ?};
>
> @@ -482,7 +492,8 @@
> ?{
> ? int opt;
>
> - ?while ((opt = getopt_long (argc, argv, "abcdfhlno:puv", options, NULL)) != -1)
> + ?while ((opt = getopt_long (argc, argv, "abcdfhilno:puv", options, NULL)) !=
> + ? ? ? ? -1)
> ? ? {
> ? ? ? switch (opt)
> ? ? ? ?{
> @@ -516,6 +527,10 @@
> ? ? ? ?case 'u':
> ? ? ? ? ?flag_unconditional = 1;
> ? ? ? ? ?break;
> + ? ? ? case 'i':
> + ? ? ? ? ?flag_intermediate_format = 1;
> + ? ? ? ? ?flag_gcov_file = 1;
> + ? ? ? ? ?break;
> ? ? ? ? case 'd':
> ? ? ? ? ? flag_display_progress = 1;
> ? ? ? ? ? break;
> @@ -531,6 +546,109 @@
> ? return optind;
> ?}
>
> +/* Get the name of the gcov file. ?The return value must be free'd.
> +
> + ? It appends the '.gcov' extension to the *basename* of the file.
> + ? The resulting file name will be in PWD.
> +
> + ? e.g.,
> + ? input: foo.da, ? ? ? output: foo.da.gcov
> + ? input: a/b/foo.cc, ? output: foo.cc.gcov ?*/
> +
> +static char *
> +get_gcov_file_intermediate_name (const char *file_name)
> +{
> + ?const char *gcov = ".gcov";
> + ?char *result;
> + ?const char *cptr;
> +
> + ?/* Find the 'basename'. ?*/
> + ?cptr = lbasename (file_name);
> +
> + ?result = XNEWVEC(char, strlen (cptr) + strlen (gcov) + 1);
> + ?sprintf (result, "%s%s", cptr, gcov);
> +
> + ?return result;
> +}
> +
> +/* Output the result in intermediate format used by 'lcov'.
> +
> +This format contains a single file named 'foo.cc.gcov', with no source
> +code included.
> +
> +SF:/home/.../foo.h
> +DA:10,1
> +DA:30,0
> +DA:35,1
> +SF:/home/.../bar.h
> +DA:12,0
> +DA:33,0
> +DA:55,1
> +SF:/home/.../foo.cc
> +FN:30,<function_name>
> +FNDA:2,<function_name>
> +DA:42,0
> +DA:53,1
> +BA:55,1
> +BA:55,2
> +DA:95,1
> +...
> +
> +The default format contains 3 separate files: 'foo.h.gcov', 'foo.cc.gcov',
> +'bar.h.gcov', each with source code included. ?*/
> +
> +static void
> +output_intermediate_file (FILE *gcov_file, source_t *src)
> +{
> + ?unsigned line_num; ? ?/* current line number. ?*/
> + ?const line_t *line; ? /* current line info ptr. ?*/
> + ?function_t *fn; ? ? ? /* current function info ptr. */
> +
> + ?fprintf (gcov_file, "SF:%s\n", src->name); ? ?/* source file name */
> +
> + ?/* NOTE: 'gcov' sometimes output 2 extra lines (including 1 EOF line)
> + ? ? in the end, search for string *EOF* in this file.
> +
> + ? ? Likely related:
> + ? ? http://gcc.gnu.org/bugzilla/show_bug.cgi?id=30257
> + ? ? http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24550 ?*/
> +
> + ?for (fn = src->functions; fn; fn = fn->line_next)
> + ? ?{
> + ? ? ?char *demangled_name;
> + ? ? ?demangled_name = cplus_demangle (fn->name, DMGL_PARAMS);
> + ? ? ?/* FN:<line_number>,<function_name> */
> + ? ? ?fprintf (gcov_file, "FN:%d,%s\n", fn->line,
> + ? ? ? ? ? ? ? demangled_name ? demangled_name : fn->name);
> + ? ? ?/* FNDA:<execution_count>,<function_name> */
> + ? ? ?fprintf (gcov_file, "FNDA:%s,%s\n",
> + ? ? ? ? ? ? ? format_gcov (fn->blocks[0].count, 0, -1),
> + ? ? ? ? ? ? ? demangled_name ? demangled_name : fn->name);
> + ? ?}
> +
> + ?for (line_num = 1, line = &src->lines[line_num];
> + ? ? ? line_num < src->num_lines;
> + ? ? ? line_num++, line++)
> + ? ?{
> + ? ? ?arc_t *arc;
> + ? ? ?if (line->exists)
> + ? ? ? ?fprintf (gcov_file, "DA:%u,%d\n", line_num,
> + ? ? ? ? ? ? ? ? line->count != 0 ? 1 : 0);
> + ? ? ?if (flag_branches)
> + ? ? ? ?for (arc = line->u.branches; arc; arc = arc->line_next)
> + ? ? ? ? ?{
> + ? ? ? ? ? ?/* BA:<line_num>,<branch_coverage_type>
> + ? ? ? ? ? ? ? ? ?branch_coverage_type: 0 (Branch not executed)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?: 1 (Branch executed, but not taken)
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?: 2 (Branch executed and taken)
> + ? ? ? ? ? ?*/
> + ? ? ? ? ? ?if (!arc->is_unconditional && !arc->is_call_non_return)
> + ? ? ? ? ? ? ?fprintf(gcov_file, "BA:%d,%d\n", line_num,
> + ? ? ? ? ? ? ? ? ? ? ?arc->src->count ? (arc->count > 0) + 1 : 0);
> + ? ? ? ? ?}
> + ? ?}
> +}
> +
> ?/* Process a single source file. ?*/
>
> ?static void
> @@ -547,7 +665,7 @@
>
> ? create_file_names (file_name);
> ? if (read_graph_file ())
> - ? ?return;
> + ? ?exit (FATAL_EXIT_CODE);
>
> ? if (!functions)
> ? ? {
> @@ -556,7 +674,7 @@
> ? ? }
>
> ? if (read_count_file ())
> - ? ?return;
> + ? ?exit (FATAL_EXIT_CODE);
>
> ? for (fn_p = NULL, fn = functions; fn; fn_p = fn, fn = fn->next)
> ? ? solve_flow_graph (fn);
> @@ -570,6 +688,8 @@
> ?{
> ? source_t *src;
> ? function_t *fn;
> + ?FILE *gcov_file_intermediate = NULL;
> + ?char *gcov_file_intermediate_name = NULL;
>
> ? for (src = sources; src; src = src->next)
> ? ? src->lines = XCNEWVEC (line_t, src->num_lines);
> @@ -587,32 +707,56 @@
> ? ? ? ?}
> ? ? }
>
> + ?if (flag_gcov_file && flag_intermediate_format)
> + ? ?{
> + ? ? ?/* We open the file now. ?*/
> + ? ? ?gcov_file_intermediate_name =
> + ? ? ? ?get_gcov_file_intermediate_name (file_name);
> + ? ? ?gcov_file_intermediate = fopen (gcov_file_intermediate_name, "w");
> + ? ?}
> ? for (src = sources; src; src = src->next)
> ? ? {
> ? ? ? accumulate_line_counts (src);
> ? ? ? function_summary (&src->coverage, "File");
> ? ? ? if (flag_gcov_file)
> ? ? ? ?{
> - ? ? ? ? char *gcov_file_name = make_gcov_file_name (file_name, src->name);
> - ? ? ? ? FILE *gcov_file = fopen (gcov_file_name, "w");
> + ? ? ? ? if (flag_intermediate_format)
> + ? ? ? ? ? /* Now output in the intermediate format without requiring
> + ? ? ? ? ? ? ?source files. ?This outputs a section to a *single* file. ?*/
> + ? ? ? ? ? output_intermediate_file (gcov_file_intermediate, src);
> + ? ? ? ? else
> + ? ? ? ? ? {
> + ? ? ? ? ? ? /* Now output the version with source files.
> + ? ? ? ? ? ? ? ?This outputs a separate *.gcov file for each source file
> + ? ? ? ? ? ? ? ?involved. ?*/
> + ? ? ? ? ? ? char *gcov_file_name = make_gcov_file_name (file_name, src->name);
> + ? ? ? ? ? ? FILE *gcov_file = fopen (gcov_file_name, "w");
>
> - ? ? ? ? if (gcov_file)
> - ? ? ? ? ? {
> - ? ? ? ? ? ? fnotice (stdout, "%s:creating '%s'\n",
> - ? ? ? ? ? ? ? ? ? ? ?src->name, gcov_file_name);
> - ? ? ? ? ? ? output_lines (gcov_file, src);
> - ? ? ? ? ? ? if (ferror (gcov_file))
> - ? ? ? ? ? ? ? ? ? fnotice (stderr, "%s:error writing output file '%s'\n",
> - ? ? ? ? ? ? ? ? ? ? ? ? ? ?src->name, gcov_file_name);
> - ? ? ? ? ? ? fclose (gcov_file);
> - ? ? ? ? ? }
> - ? ? ? ? else
> - ? ? ? ? ? fnotice (stderr, "%s:could not open output file '%s'\n",
> - ? ? ? ? ? ? ? ? ? ?src->name, gcov_file_name);
> - ? ? ? ? free (gcov_file_name);
> - ? ? ? }
> - ? ? ?fnotice (stdout, "\n");
> + ? ? ? ? ? ? if (gcov_file)
> + ? ? ? ? ? ? ? {
> + ? ? ? ? ? ? ? ? fnotice (stdout, "%s:creating '%s'\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ?src->name, gcov_file_name);
> + ? ? ? ? ? ? ? ? output_lines (gcov_file, src);
> + ? ? ? ? ? ? ? ? if (ferror (gcov_file))
> + ? ? ? ? ? ? ? ? ? fnotice (stderr, "%s:error writing output file '%s'\n",
> + ? ? ? ? ? ? ? ? ? ? ? ? ? ?src->name, gcov_file_name);
> + ? ? ? ? ? ? ? ? fclose (gcov_file);
> + ? ? ? ? ? ? ? }
> + ? ? ? ? ? ? else
> + ? ? ? ? ? ? ? fnotice (stderr, "%s:could not open output file '%s'\n",
> + ? ? ? ? ? ? ? ? ? ? ? ?src->name, gcov_file_name);
> + ? ? ? ? ? ? free (gcov_file_name);
> + ? ? ? ? ? }
> + ? ? ? ? fnotice (stdout, "\n");
> + ? ? ? ?}
> ? ? }
> +
> + ?if (flag_gcov_file && flag_intermediate_format)
> + ? ?{
> + ? ? ?/* Now we've finished writing the intermediate file. ?*/
> + ? ? ?fclose (gcov_file_intermediate);
> + ? ? ?XDELETEVEC (gcov_file_intermediate_name);
> + ? ?}
> ?}
>
> ?/* Release all memory used. ?*/
> @@ -841,6 +985,7 @@
> ? ? ? ? ?functions = fn;
> ? ? ? ? ?current_tag = tag;
>
> + ? ? ? ? ?/* NOTE: Here is how *EOF* comes to effect. ?*/
> ? ? ? ? ?if (lineno >= src->num_lines)
> ? ? ? ? ? ?src->num_lines = lineno + 1;
> ? ? ? ? ?/* Now insert it into the source file's list of
> @@ -949,6 +1094,7 @@
> ? ? ? ? ? ? ? ? ? ? ?line_nos[ix++] = src->index;
> ? ? ? ? ? ? ? ? ? ?}
> ? ? ? ? ? ? ? ? ?line_nos[ix++] = lineno;
> + ? ? ? ? ? ? ? ? ?/* NOTE: Here is how *EOF* comes to effect. ?*/
> ? ? ? ? ? ? ? ? ?if (lineno >= src->num_lines)
> ? ? ? ? ? ? ? ? ? ?src->num_lines = lineno + 1;
> ? ? ? ? ? ? ? ?}
> Index: testsuite/g++.dg/gcov/gcov-7.C
> ===================================================================
> --- testsuite/g++.dg/gcov/gcov-7.C ? ? ?(revision 0)
> +++ testsuite/g++.dg/gcov/gcov-7.C ? ? ?(revision 0)
> @@ -0,0 +1,32 @@
> +/* Verify that intermediate coverage format can be generated for simple code. */
> +
> +/* { dg-options "-fprofile-arcs -ftest-coverage" } */
> +/* { dg-do run { target native } } */
> +
> +class C {
> +public:
> + ?C()
> + ?{
> + ? ?i = 0; ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* count(1) */
> + ?}
> + ?~C() {}
> + ?void seti (int j)
> + ?{
> + ? ?i = j; ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* count(1) */
> + ?}
> +private:
> + ?int i;
> +};
> +
> +void foo()
> +{
> + ?C c; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* count(2) */
> + ?c.seti (1); ? ? ? ? ? ? ? ? ? ? ? ? ?/* count(1) */
> +}
> +
> +int main()
> +{
> + ?foo(); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? /* count(1) */
> +}
> +
> +/* { dg-final { run-gcov { -i gcov-7.C } } } */
>
> --
> This patch is available for review at http://codereview.appspot.com/4595053
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]