Skip to content

Commit 8ed5a40

Browse files
committed
Adds initial page for using gcov for code coverage.
1 parent 019eb1e commit 8ed5a40

File tree

2 files changed

+178
-0
lines changed

2 files changed

+178
-0
lines changed

doc/sphinx/source/debugging/debug.rst

+1
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ This is very much work in progress. I will add to it/correct it as I develop new
1818
valgrind
1919
leak_newrefs_vg
2020
debug_tactics
21+
gcov

doc/sphinx/source/debugging/gcov.rst

+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
.. highlight:: python
2+
:linenothreshold: 10
3+
4+
.. highlight:: c
5+
:linenothreshold: 10
6+
7+
.. toctree::
8+
:maxdepth: 3
9+
10+
.. _gcov-label:
11+
12+
===============================================
13+
Using gcov for C/C++ Code Coverage
14+
===============================================
15+
16+
This is about how to run your C/C++ code using gcov to gather coverage metrics.
17+
18+
.. note::
19+
20+
These instructions have been tested on Mac OS X 10.9 (Mavericks).
21+
They may or may not work on other OS's
22+
23+
24+
.. _gcov-mac-osx-label:
25+
26+
---------------------------
27+
gcov under Mac OS X
28+
---------------------------
29+
30+
31+
^^^^^^^^^^^^^^^^^
32+
Configuring Xcode
33+
^^^^^^^^^^^^^^^^^
34+
35+
`This document <https://developer.apple.com/library/mac/qa/qa1514/_index.html>`_ tells you how to configure Xbuild for gcov (actually llvm-cov).
36+
37+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
38+
Running and Analysing Code Coverage
39+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
40+
41+
In Xcode select Product->Run then once that has completed note the GCov_build directory in Xcode by selecting Products-><project> in the left hand pane. In the right hand pane under 'Identity and Type' you should see 'Full Path' of something like::
42+
43+
/Users/$USER/Library/Developer/Xcode/DerivedData/<project name and hash>/Build/Products/GCov_Build/<project>
44+
45+
In the Terminal navigate to the 'Build' directory:
46+
47+
.. code-block:: bash
48+
49+
$ cd cd /Users/$USER/Library/Developer/Xcode/DerivedData/<project name and hash>/Build/
50+
51+
Now navigate to the Intermediates/ directory and in there you should find the code coverage data in a path such as this:
52+
53+
.. code-block:: bash
54+
55+
cd Intermediates/<project>.build/GCov_Build/<project>.build/Objects-normal/x86_64
56+
57+
In there the interesting file has a .gcno extension. To convert this into something readable we need to run gcov on it. We can use xcrun to find gcov and this gives an overall code coverage number for each file (and its includes):
58+
59+
.. code-block:: bash
60+
61+
$ xcrun gcov TimeBDT.gcno
62+
...
63+
File 'TimeBDT.cpp'
64+
Lines executed:87.18% of 78
65+
TimeBDT.cpp:creating 'TimeBDT.cpp.gcov'
66+
...
67+
68+
This has now generated a detailed file TimeBDT.cpp.gcov that contains line by line coverage:
69+
70+
.. code-block:: bash
71+
72+
$ ls -l TimeBDT.*
73+
-rw-r--r-- 1 paulross staff 14516 6 Oct 18:48 TimeBDT.cpp.gcov
74+
-rw-r--r-- 1 paulross staff 248 6 Oct 18:38 TimeBDT.d
75+
-rw-r--r-- 1 paulross staff 1120 6 Oct 18:38 TimeBDT.dia
76+
-rw-r--r-- 1 paulross staff 32252 6 Oct 18:45 TimeBDT.gcda
77+
-rw-r--r-- 1 paulross staff 121444 6 Oct 18:38 TimeBDT.gcno
78+
-rw-r--r-- 1 paulross staff 3671 6 Oct 18:48 TimeBDT.h.gcov
79+
-rw-r--r-- 1 paulross staff 310496 6 Oct 18:38 TimeBDT.o
80+
$ cat TimeBDT.cpp.gcov | less
81+
...
82+
-: 208:/* Returns the total number of seconds in this particular year. */
83+
-: 209:time_t TimeBDTMapEntry::secsInThisYear() const {
84+
6000000: 210: return _isLeap ? SECONDS_IN_YEAR[1] : SECONDS_IN_YEAR[0];
85+
-: 211:}
86+
...
87+
-: 289: } else {
88+
#####: 290: if (pTimeBDT->ttYearStart() > tt) {
89+
#####: 291: --year;
90+
#####: 292: } else {
91+
#####: 293: ++year;
92+
-: 294: }
93+
-: 295: }
94+
95+
The first snippet shows that line 210 is executed 6000000 times. In the second snippet the ``#####`` shows that lines 290-293 have not executed at all.
96+
97+
.. _gcov-cpython-code-label:
98+
99+
----------------------------------------------------------
100+
Using gcov on CPython Extensions
101+
----------------------------------------------------------
102+
103+
Whilst it is common to track code coverage in Python test code it gets a bit more tricky with Cpython extensions as Python code coverage tools can not track C/C++ extension code. The solution is to use ``gcov`` and run the tests in a C/C++ process by embedding the Python interpreter.
104+
105+
.. code-block:: c++
106+
107+
#include <Python.h>
108+
109+
int test_cpython_module_foo_functions(PyObject *pModule) {
110+
assert(pModule);
111+
int fail = 0;
112+
try:
113+
/* foo.function(...) */
114+
pFunc = PyObject_GetAttrString(pModule, "function");
115+
if (pFunc && PyCallable_Check(pFunc)) {
116+
117+
pValue = PyObject_CallObject(pFunc, pArgs);
118+
}
119+
/*
120+
* Test other Foo functions here
121+
*/
122+
except:
123+
assert(fail != 0);
124+
finally:
125+
return fail;
126+
}
127+
128+
int test_cpython_module_foo() {
129+
int fail = 0;
130+
PyObject *pName = NULL;
131+
try:
132+
pName = PyUnicode_FromString("foo");
133+
if (! pName) {
134+
fail = 1;
135+
goto except;
136+
}
137+
pModule = PyImport_Import(pName);
138+
if (! pModule) {
139+
fail = 2;
140+
goto except;
141+
}
142+
/* foo.function(...) */
143+
pFunc = PyObject_GetAttrString(pModule, "function");
144+
if (pFunc && PyCallable_Check(pFunc)) {
145+
146+
pValue = PyObject_CallObject(pFunc, pArgs);
147+
}
148+
/*
149+
* Test other Foo functions here
150+
*/
151+
except:
152+
assert(fail != 0);
153+
finally:
154+
Py_XDECREF(pName);
155+
Py_XDECREF(pModule);
156+
return fail;
157+
}
158+
159+
void test_cpython_code() {
160+
Py_SetProgramName("TestCPythonExtensions"); /* optional, recommended */
161+
Py_Initialize();
162+
test_cpython_module_foo();
163+
/*
164+
* Test other modules here
165+
*/
166+
Py_Finalize();
167+
}
168+
169+
int main(int argc, const char * argv[]) {
170+
std::cout << "Testing starting" << std::endl;
171+
test_cpython_code();
172+
/*
173+
* Non-CPython code tests here...
174+
*/
175+
std::cout << "Testing DONE" << std::endl;
176+
return 0;
177+
}

0 commit comments

Comments
 (0)