lcov icon indicating copy to clipboard operation
lcov copied to clipboard

allow paralell gcda processing/avoid temporary files in base directory

Open pspacek opened this issue 7 years ago • 7 comments

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!

pspacek avatar Jan 02 '18 15:01 pspacek

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!

olipratt avatar Feb 10 '18 21:02 olipratt

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.

oberpar avatar Feb 12 '18 09:02 oberpar

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.

xaizek avatar Feb 12 '18 16:02 xaizek

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

olipratt avatar Feb 12 '18 18:02 olipratt

@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.

xaizek avatar Feb 12 '18 19:02 xaizek

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!

chenhaoc avatar Jun 28 '22 04:06 chenhaoc

sorry, my lcov version 1.4 is too old. lcov1.6 support parallel process now, everything is perfect now

chenhaoc avatar Jun 28 '22 07:06 chenhaoc

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?

wolfo1 avatar Oct 23 '22 13:10 wolfo1

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

henry2cox avatar Oct 24 '22 11:10 henry2cox

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

henry2cox avatar Dec 08 '22 11:12 henry2cox

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

henry2cox avatar May 11 '23 10:05 henry2cox