gcov is not generating coverage information for header files
I'm using gcov for the first time and I'm having a problem which is similar to the one reported in this thread. However, I wasn't able to solve my problem following the comments in that thread.
I'm trying to measure the coverage of a concrete test case in KMyMoney-4.6.4, namely "testConstructor" in the test file "mymoneyaccounttest.cpp". This test case is using the following method, which is in the header file "mymoneyaccount.h" and has executable code:
const QString& institutionId(void) const {
return m_institution;
}
So, I build the program and the tests, and then execute: gcov mymoneyaccount.cpp
Among the coverage information displayed, I obtain:
... File 'mymoneyaccount.cpp' Lines executed:8.91% of 393 Creating 'mymoneyaccount.cpp.gcov'
File 'mymoneyaccount.h' Lines executed:25.00% of 4 Creating 'mymoneyaccount.h.gcov' ...
The coverage information in "mymoneyaccount.cpp.gcov" is ok. In contrast, "mymoneyaccount.h.gcov" shows:
6: 81:class KMM_MYMONEY_EXPORT MyMoneyAccount : public MyMoneyObject, public MyMoneyKeyValueContainer
...
-: 192: const QString& institutionId(void) const {
-: 193: return m_institution;
-: 194: }
...
-: 272: int accountCount(void) const {
#####: 273: return m_accountList.count();
-: 274: };
Maybe I'm wrong, but this result means that gcov is not considering "return m_institution;" as executable code while does it considering "return m_accountList.count()" as executable code. Moreover, it shows "6" in the line of the class declaration, so this file has coverage information but not what I was expecting.
I have to say that maybe the problem has to do with the names of the files and the directories:
1- The object files are created in "CMakefiles/kmm_mymoney.dir" ending with ".cpp.o", for instance, mymoneyaccount.cpp.o. Thus, the "gcno" and "gcda" files are created with the name "mymoneyaccount.cpp.gcno" and "mymoneyaccount.cpp.gcda" (of course, in the directory "CMakefiles/kmm_mymoney.dir").
2- When I execute: gcov -o CMakeFiles/kmm_mymoney.dir mymoneyaccount.cpp gcov gives the following error:
mymoneyaccount.gcno:cannot open notes file
So I have to rename those files: mv mymoneyaccount.cpp.gcno mymoneyaccount.gcno mv mymoneyaccount.cpp.gcda mymoneyaccount.gcda
Finally, I have another question. When I execute gcov in the file containing the test cases, I mean, "gcov mymoneyaccounttest.cpp" instead of "gcov mymoneyaccount.cpp", I also obtain a "mymoneyaccount.h.gcov" file, but the coverage information is even worse:
#####: 81:class KMM_MYMONEY_EXPORT MyMoneyAccount : public MyMoneyObject, public MyMoneyKeyValueContainer
Anyway, the question is: should I execute "gcov" on the implementation file "mymoneyaccount.cpp" or in the test file "mymoneyaccounttest.cpp"?
Sorry for the length. Thanks.
Thank you very much Tony!! That link had the solution. I just changed the optimization from -O2 to -O0 and now the result is:
1: 192: const QString& institutionId(void) const {
1: 193: return m_institution;
-: 194: }
I have to note that to obtain "mymoneyaccount.cpp.gcov" I execute "gcov mymoneyaccount.cpp", but to obtain "mymoneyaccount.h.gcov" I have to execute "gcov mymoneyaccounttest.cpp". Do you know why? Both files include "mymoneyaccount.h".
has coverage information but not what I was expecting.
This is maybe an XY problem, because you think that your program executes in a way you believe but it simply runs totally different.
I will show you a very simple program:
class Example
{
private:
int value;
public:
Example(const Example& in): value(in.value)
{
std::cout << "Here we copy" << std::endl;
}
Example(int _value): value(_value)
{
std::cout << "Runs with default" << std::endl;
}
Example( Example&& in): value( in.value)
{
std::cout << "Moved away" << std::endl;
}
void show()
{
std::cout << "value " << value << std::endl;
}
};
Example GetIt()
{
return Example(2);
}
int main()
{
Example ex(Example(1));
ex.show();
std::cout << "----------------" << std::endl;
Example ex2( GetIt());
ex2.show();
}
The output is:
Runs with default
value 1
Runs with default
value 2
As you can see, there is no copy constructor called as you could expect and also there is no move constructor called. The construction is simply elided! So what do you expect gcov prints out? Simply it prints the call to the direct call to the constructor with int parameter. Nothing else!
You say:
I require to have the full coverage information...
There is simply no way to get more information as the truth!
If your expectation is completely different to what you get from your analyzing tool, check if your assumptions are true. For my expectations the tools gcov and gprof are really good and the instrumentation of code works nearly perfect. But code which will optimized away will not generate any debug/profiling/coverage information. With debug it is not always true, because newer versions of gcc generate some meta information which give a link to the original source code which enables to set breakpoints also if the code is not longer present in the executable. But for elided constructors there is nothing present also while debugging because the program flow is simply changed! No cout
, no call to the constructor and no further information for profiling/coverage. The code is simply not executed and simply not in use. As you can see, the cout
is not called! This simply tells you that the code is "modified" to operate in an other way as you have coded it!
My example shows only one aspect of optimizing! This is only eliding! There are a lot of other optimizing steps and strategies, also with O0
! Remark that my code was compiled with O0
and the copy construction was moved away!
Hints:
If your debug/coverage/profiling looks different to your expectations: Look at the assembly to find out what is really executed and which source lines are involved. You can call objdump to get the source and assembler intermixed for this!
If you scale down your optimizer, keep in mind your program simply runs different code. Results can not be taken without a "intelligent" interpretation. This needs a bit of experience how to deal with such data.
If you are really have a need for "full" information, ask why!
If you think you get not enough information on a program execution path, you should be happy! Normally this exactly tells you, that your execution is shortened a bit by optimzing.
And if you get no profiling information on a single line/method: Simply look at the block which uses/calls this functionality. Mostly the time consumption is as short that further investigation is useless.
I want to complete the answer that I gave to @Klaus.
Both combinations "-O2 -g" and "-O2" gives the following coverage information for this method (I inserted the message only to be sure that the method was being executed in the tests):
-: 192: const QString& institutionId(void) const {
1: 193: std::cout << "Inside institutionIdn";
-: 194: return m_institution;
-: 195: }
That means that the lines 192 and 194 are not considered as executable, but only the cout. The flag -g does not affect the result (at least in this case).
If I build the program using "-O0", the result is:
1: 192: const QString& institutionId(void) const {
1: 193: std::cout << "Inside institutionIdn";
1: 194: return m_institution;
-: 195: }
链接地址: http://www.djcxy.com/p/51012.html
上一篇: LLVM优化器无法处理简单的情况?
下一篇: gcov不会生成头文件的覆盖率信息