Misurare la copertura della libreria C chiamata nel processo Python
Domanda
Vorrei iniziare con l'esempio: chiamare il codice della libreria da Python.
Questo è il codice della libreria (compilato in libreria libfoolib
):
#include <stdio.h>
void bar()
{
printf("bar\n");
}
void foo()
{
printf("foo\n");
}
E questo è il codice Python che lo chiama:
#!/usr/bin/python25
import sys
import libfoolib
import processing
def callFoo():
libfoolib.foo()
libfoolib.bar()
process = processing.Process(target=callFoo)
process.start()
Quando la libreria viene compilata con -ftest-coverage
e -fprofile-arcs
il compilatore genera correttamente gcno
file e quando il codice Python viene eseguito il gcda
Anche il file viene generato. Il problema è che contiene solo numeri di copertura per bar
funzione che viene chiamata prima del biforcimento del pitone. se la foo
È stato anche chiamato al di fuori della chiamata di elaborazione di Python, quindi tutto è buono.
Questo è quello che ottengo quando corro gcov
Strumento sui dati di copertura prodotti:
-: 0:Source:/codeCoverageTests/pythonSIP/foo.c
-: 0:Graph:debug/CMakeFiles/fooLib.dir/foo.c.gcno
-: 0:Data:debug/CMakeFiles/fooLib.dir/foo.c.gcda
-: 0:Runs:4
-: 0:Programs:1
-: 1:#include <stdio.h>
-: 2:
-: 3:void bar()
function bar called 4 returned 100% blocks executed 100%
4: 4:{
4: 5: printf("bar\n");
call 0 returned 100%
4: 6:}
-: 7:
-: 8:void foo()
function foo called 0 returned 0% blocks executed 0%
#####: 9:{
#####: 10: printf("foo\n");
call 0 never executed
#####: 11:}
-: 12:
La domanda che ho è "dov'è il mio foo
Dati di copertura? "
Alcuni ulteriori dettagli sull'ambiente:
- CentOS 5.4
- GCC: 4.1.2 20080704 (Red Hat 4.1.2-46)
- Cmake Build (versione 2.8.0)
- Python 2.5
- Python to C utilizza SIP (versione 4.7.4)
Soluzione
Il problema è che la libreria di elaborazione di Python sta uscendo usando os._exit
. Questo è un problema poiché uscire in questo modo non chiama i normali gestori di pulizia del processo. Si scopre che la strumentazione raccoglie i dati di copertura nei buffer e lo scrive solo all'uscita del processo e lo fa nei gestori di pulizia del processo regolari. A causa di tali interazioni il processo del bambino non ha mai l'opportunità di scrivere i propri dati e l'invocazione di foo
Non viene mai scritto.
Per risolvere questo obiettivo, sto chiamando __gcov_flush
manualmente prima della fine del mio processo. E poiché questa è una libreria statica, c'è bisogno di un piccolo tb solo per quel lavoro.