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: [PATCH] Add an intermediate coverage format for gcov


Sorry about the garbled message. My mistake with the mailer. Here
is what I really intended to send.
----

This patch was earlier submitted to google/main, but I propose itfor
trunk as well.
This patch adds an intermediate coverage format (enabled via
'gcov-i'). This is a compact format as it does not require source
files.
The new option ('gcov -i') outputs .gcov files in an intermediate
textformat that can be postprocessed by lcov or other applications.
Itwill output a single *.gcov file per *.gcda file. No source code
isrequired.
The format of the intermediate .gcov file is plain text with one entryper line
  SF:source_file_name  FN:line_number,function_name
FNDA:execution_count,function_name  BA:line_num,branch_coverage_type
 Â DA:line number,execution_count
  Where the branch_coverage_type is   Â0 (Branch not executed)
 Â1 (Branch executed, but not taken)   Â2 (Branch executed and
taken)
There can be multiple SF entries in an intermediate gcov file.
Allentries following SF pertain to that source file until the next
SFentry.
A concrete example looks like this:
 SF:array.c FN:4,sum FNDA:0,sum FN:13,main FNDA:1,main DA:4,2
BA:8,2Â DA:7,1
I have bootstrapped and tested this patch on x86_64-linux. No new
testfailures were observed.
Okay for trunk?
Thanks,Sharad

2011-10-04 Â Sharad Singhai Â<singhai@google.com>
	* doc/gcov.texi: Document gcov intermediate format.	* gcov.c
(print_usage): Handle new option.	(process_args): Handle new
option.	(get_gcov_file_intermediate_name): New
function.	(output_intermediate_file): New
function.	(generate_results): Handle new option.	*
testsuite/lib/gcov.exp: Handle intermediate format.	*
testsuite/g++.dg/gcov/gcov-8.C: New testcase.
Index: doc/gcov.texi===================================================================---
doc/gcov.texi	(revision 179475)+++ doc/gcov.texi	(working copy)@@
-130,6 +130,7 @@ gcov [@option{-v}|@option{--version}] [@
[@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,32 @@ Unconditional branches are normally not
@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.++The format of the intermediate @file{.gcov}
file is plain text with+one entry per
line++@smallexample+SF:@var{source_file_name}+FN:@var{line_number},@var{function_name}+FNDA:@var{execution_count},@var{function_name}+BA:@var{line_num},@var{branch_coverage_type}+DA:@var{line
number},@var{execution_count}++Where the @var{branch_coverage_type}
is+ Â 0 (Branch not executed)+ Â 1 (Branch executed, but not taken)+
2 (Branch executed and taken)++There can be multiple SF entries in an
intermediate gcov file. All+entries following SF pertain to that
source file until the next SF+entry.+@end smallexample+Â@end table
@command{gcov} should be run with the current directory the same as
thatIndex: gcov.c===================================================================---
gcov.c	(revision 179475)+++ gcov.c	(working copy)@@ -39,6 +39,7 @@
along with Gcov; see the file COPYING3.ÂÂ#include "intl.h"Â#include
"diagnostic.h"Â#include "version.h"+#include "demangle.h"ÂÂ#include
<getopt.h>Â@@ -311,6 +312,9 @@ static int flag_gcov_file = 1;ÂÂ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 @@ print_usage (int error_p)Â Â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 @@ static const struct option
options[] =Â Â{ "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 @@ process_args (int argc, char **argv)Â{Â Â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 @@ process_args (int argc, char **argv)
	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,107 @@ process_args (int argc, char **argv)
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'.++The intermediate 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. Likely
related:+ Â Â http://gcc.gnu.org/bugzilla/show_bug.cgi?id=15369+ Â*/++
Â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@@ -570,6 +686,8 @@
generate_results (const char *file_name)Â{Â Â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,31 +705,55 @@ generate_results (const char *file_name)Â	}Â Â Â}Â+
Âif (flag_gcov_file && flag_intermediate_format)+ Â Â{+ Â Â Â/* Open
the intermediate file. Â*/+ Â Â Â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 (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_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 (flag_gcov_file &&
flag_intermediate_format)+ Â Â{+ Â Â Â/* Now we've finished writing
the intermediate file. Â*/+ Â Â Âfclose (gcov_file_intermediate);+
ÂXDELETEVEC (gcov_file_intermediate_name);Â Â Â}Â}ÂIndex:
testsuite/lib/gcov.exp===================================================================---
testsuite/lib/gcov.exp	(revision 179475)+++
testsuite/lib/gcov.exp	(working copy)@@ -60,6 +60,59 @@ proc
verify-lines { testcase file } {Â}ÂÂ#+# verify-intermediate -- check
that intermediate file has certain lines+#+# TESTCASE is the name of
the test.+# FILE is the name of the gcov output file.+#+# Checks are
very loose, they are based on being certain tags present+# in the
output. They do not check for exact expected execution+# counts. For
that the regular gcov format should be checked.+#+proc
verify-intermediate { testcase file } {+ Â Âset failed 0+ Â Âset sf 0+
 Âset fn 0+  Âset fnda 0+  Âset da 0+  Âset fd [open $file r]+
while { [gets $fd line] >= 0 } {+	if [regexp "^SF:" $line] {+	 Â Âincr
sf+	}+	if [regexp "^FN:(\[0-9\]+)," $line] {+	 Â Âincr fn+	}+	if
[regexp "^FNDA:(\[0-9\]+)," $line] {+	 Â Âincr fnda+	}+	if [regexp
"^DA:(\[0-9\]+),(\[0-9\]+)" $line] {+	 Â Âincr da+	}+ Â Â}++ Â Â# We
should see at least one tag of each type+ Â Âif {$sf == 0} {+	fail
"expected SF: not found"+	incr failed+ Â Â}+ Â Âif {$fn == 0} {+	fail
"expected FN: not found"+	incr failed+ Â Â}+ Â Âif {$fnda == 0}
{+	fail "expected FNDA: not found"+	incr failed+ Â Â}+ Â Âif {$da ==
0} {+	fail "expected DA: not found"+	incr failed+ Â Â}+ Â Âreturn
$failed+}+++#Â# verify-branches -- check that branch percentages are
as expectedÂ#Â# TESTCASE is the name of the test.@@ -234,6 +287,8 @@
proc run-gcov { args } {ÂÂ Â Âset gcov_verify_calls 0Â Â Âset
gcov_verify_branches 0+ Â Âset gcov_verify_lines 1+ Â Âset
gcov_verify_intermediate 0Â Â Âset gcov_execute_xfail ""Â Â Âset
gcov_verify_xfail ""Â@@ -242,6 +297,11 @@ proc run-gcov { args } {Â	
set gcov_verify_calls 1Â	} elseif { $a == "branches" } {Â	 Âset
gcov_verify_branches 1+	} elseif { $a == "intermediate" } {+	 Âset
gcov_verify_intermediate 1+	 Âset gcov_verify_calls 0+	 Âset
gcov_verify_branches 0+	 Âset gcov_verify_lines 0Â	}Â Â Â}Â@@ -274,8
+334,12 @@ proc run-gcov { args } {Â	eval setup_xfail [split
$gcov_verify_xfail]Â Â Â}Â- Â Â# Check that line execution counts are
as expected.- Â Âset lfailed [verify-lines $testcase $testcase.gcov]+
 Âif { $gcov_verify_lines } {+	# Check that line execution counts are
as expected.+	set lfailed [verify-lines $testcase $testcase.gcov]+
} else {+	set lfailed 0+ Â Â}ÂÂ Â Â# If requested via the .x file,
check that branch and call information  Â# is correct.@@ -289,12
+353,18 @@ proc run-gcov { args } {Â Â Â} else {Â	set cfailed 0Â Â Â}+
 Âif { $gcov_verify_intermediate } {+	# Check that intermediate
format has the expected format+	set ifailed [verify-intermediate
$testcase $testcase.gcov]+ Â Â} else {+	set ifailed 0+ Â Â}ÂÂ Â Â#
Report whether the gcov test passed or failed. ÂIf there were  Â#
multiple failures then the message is a summary.- Â Âset tfailed [expr
$lfailed + $bfailed + $cfailed]+ Â Âset tfailed [expr $lfailed +
$bfailed + $cfailed + $ifailed]Â Â Âif { $tfailed > 0 } {-	fail
"$subdir/$testcase gcov: $lfailed failures in line counts, $bfailed in
branch percentages, $cfailed in return percentages"+	fail
"$subdir/$testcase gcov: $lfailed failures in line counts, $bfailed in
branch percentages, $cfailed in return percentages, $ifailed in
intermediate format"Â Â Â} else {Â	pass "$subdir/$testcase gcov"
	clean-gcov $testcaseIndex:
testsuite/g++.dg/gcov/gcov-8.C===================================================================---
testsuite/g++.dg/gcov/gcov-8.C	(revision 0)+++
testsuite/g++.dg/gcov/gcov-8.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 intermediate { -i gcov-8.C } }
} */


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