lcov
lcov copied to clipboard
allow paralell gcda processing/avoid temporary files in base directory
Hello,
it seems that lcov/geninfo uses directory specified by --base-directory
parameter for temporary files. This breaks parallel execution of multiple lcov instances on the same base directory, or of base-directory
is read-only for any reason.
Parallel execution might sound weird at first, but it makes sense for programs which are executed in parallel and test coverage needs to be combined from all individual runs.
I have hundreds of .gcda
and .gcno
trees from the same program (which was run in parallel and gcda files redirected elsewhere) and now I'm attempting to create individual .info
files for each run and then combine all .info
files into the final info file used for genhtml
.
While doing this, I attempted to speed up the process by executing lcov in parallel:
lcov -q --base-directory '$(TOPSRCDIR)' --no-external --capture -d daemon -o tempfile$(n).info
but lcov processing fails with following errors:
geninfo: WARNING: cannot find an entry for #usr#include#bits#stdio2.h.gcov in .gcno file, skipping file!
Further inspection of strace output showed that lcov creates these files in base-directory
.
Please consider creating temporary files outside of temporary directory. Thank you!
I've basically been doing the same thing here and been hitting the same problem - trying to process separate trees of .gcda
and .gcno
files (generated by compiling the same source files and then running tests in parallel first) by running multiple instances of LCOV over them in parallel hits these errors.
I don't think this is really LCOV's fault though - from the gcov docs:
gcov should be run with the current directory the same as that when you invoked the compiler. [...] One .gcov file is produced for each source (or header) file containing code, which was compiled to produce the data files. The mangledname part of the output file name is usually simply the source file name, but can be something more complicated if the ‘-l’ or ‘-p’ options are given.
So the issue here is that the parallel LCOV instances are forced to run gcov
sub-processes in the same directory, these gcov instances generate files with the same names, and carnage ensues.
From looking at bit more at gcov
, the only reason it has this requirement on being run in that same directory as the source was compiled in is so that it can find the source files to build its output files. However, it seems a few years ago it added an 'intermediate format', again covered in the docs produced when passing the -i
option - which even specifically mentions LCOV as a use case! This doesn't need access to the source files at all, so can be run from any directory, and from what I can see contains the exact same data as in the LCOV .info
files, just with slightly different formatting.
So it would be really helpful here if LCOV (I think actually the geninfo
tool) was enhanced to support calling through to gcov
passing the -i
option (checking that the gcov version supports -i
for compatibility), running it in the same directory as the .gcda
file exists which produces <filename>.gcda.gcov
, then geninfo
just transforms the contents of that file into the same .info
file as normal.
This then I think has a few benefits:
- LCOV is faster - it no longer calls through to
gcov
to pull in all the source file information into a file that LCOV then immediately parses out and throws it away. - LCOV instances can be run in parallel over separate trees of
.gcno
and.gcda
files because there's no generation of files with the same name in the same directory by parallel instances.
Is there any desire to enhance LCOV with this kind of support? I'd be willing to help here if I can, though I can't say I've ever written any perl :)
Thanks!
I've seen the --intermediate option of gcov but it doesn't seem to work the way it is advertised:
Compiler version:
# gcc --version
gcc (GCC) 7.2.1 20170915 (Red Hat 7.2.1-2)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.`
Source files:
# cat *.c
/* a.c */
int fn()
{
return 1;
}
/* b.c */
int fn2()
{
return -1;
}
/* test.c */
#include "a.c"
#include "b.c"
int main()
{
return fn() + fn2();
}
Result of running gcov:
# gcc test.c -o test --coverage
# ./test
# ls *.gcda
test.gcda
# gcov --intermediate test.c
File 'test.c'
Lines executed:100.00% of 2
Creating 'test.c.gcov'
File 'b.c'
Lines executed:100.00% of 2
Creating 'b.c.gcov'
File 'a.c'
Lines executed:100.00% of 2
Creating 'a.c.gcov'
# ls *.gcov
a.c.gcov b.c.gcov test.c.gcov
As you can see, even when --intermediate
is specified, multiple output files are created. This precludes its use to implement parallel .gcda processing in lcov. Given the description in gcov's man page, this could be considered a bug in GCC:
The output is a single .gcov file per .gcda file.
Unfortunately I didn't have time to follow up on this yet. If you want to help, your could try opening a GCC bug report to see whether this is in fact a bug.
I think bug#82702 was about this issue with intermediate format (although it says that only one file was produced prior to GCC 6, my gcc 5.5.0 creates multiple files as well). It supposed to be fixed by this commit.
Hi - thanks for the quick response.
Tested your scenario on my gcc
at 4.9.2 and I only get a single .gcov
file, so agree with @xaizek this looks like that specific bug:
$ ls
a.c b.c test test.c test.c.gcov test.gcda test.gcno
I think this is still a useful enhancement for many cases - maybe support could be added by passing a specific flag to lcov
, or disabled by default for say known broken gcc versions? (Though that linked GCC bug seems to be caused by this commit only present in releases 7.1/7.2/7.3 - but @xaizek you are seeing one gcov
file per .c
file on 5.5.0?)
The behaviour is correct in my normal scenario where I compile each source file into individual .o
files then link - I've given an example below tweaking your example, just for the record.
My Use Case
Compiler
$ gcc --version
gcc (GCC) 4.9.2 20150212 (Red Hat 4.9.2-6)
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Files
$ cat *.c
/* a.c */
int fn()
{
return 1;
}
/* b.c */
int fn2()
{
return -1;
}
/* test.c */
// #include "a.c"
// #include "b.c"
int fn();
int fn2();
int main()
{
return fn() + fn2();
}
Compiling, linking, and gcov
$ gcc -c test.c -o test.o --coverage
$ gcc -c a.c -o a.o --coverage
$ gcc -c b.c -o b.o --coverage
$ gcc a.o b.o test.o -o test --coverage
$ ./test
$ gcov --intermediate test.gcda
File 'test.c'
Lines executed:100.00% of 2
$ gcov --intermediate a.gcda
File 'a.c'
Lines executed:100.00% of 2
$ gcov --intermediate b.gcda
File 'b.c'
Lines executed:100.00% of 2
@xaizek you are seeing one gcov file per .c file on 5.5.0?
Yes, because that commit was backported: https://github.com/gcc-mirror/gcc/commit/ac470b78b552247be1d42fae5539f6ab18b12a97 So some earlier version of GCC 5 must have worked fine.
And now this comment from the bug makes sense:
It's quite risky backport. I'm sorry, but I'm not planning to backport the fix.
seems this problem not fixed yet? lcov processing parallelly with following errors: geninfo: WARNING: cannot find an entry for xxx.h.gcov in .gcno file, skipping file!
sorry, my lcov version 1.4 is too old. lcov1.6 support parallel process now, everything is perfect now
seems this problem not fixed yet? lcov processing parallelly with following errors: geninfo: WARNING: cannot find an entry for xxx.h.gcov in .gcno file, skipping file!
Hey, I am running into the same problem with lcov version 1.14. The version is the only thing which caused the error for you?
Do you have a small testcase that illustrates the issue? I would like to try it, with my version of code.
(Amongst other things, I had implemented a “--parallel” flag for lcov, genhtml, and geninfo – to use multiple cores to improve runtime performance. That is not quite the same application as yours, but is somewhat related.) Thanks
Henry
BTW: I think that this is fixed now. See the --tempdir option. If you see something that doesn't work correctly, please upload a testcase and/or give a detailed description of how to cause an issue.
Thanks Henry
No comments or update in 6 months. I believe this issue is addressed/fixed - so closing the issue.
If there is still a problem: please reopen this issue or file a new issue. Please provide a detailed description of the problem, and ideally provide a (small) testcase which illustrates the issue. Henry