2011-03-21 12 views
64

Sto provando a generare un grafo chiamante con cui scoprire tutti i possibili percorsi di esecuzione che stanno colpendo una funzione particolare (in modo da non dover calcolare manualmente tutti i percorsi, come ci sono molti percorsi che portano a questa funzione). Per esempio:Genera grafico chiamante per codice C++

path 1: A -> B -> C -> D 
path 2: A -> B -> X -> Y -> D 
path 3: A -> G -> M -> N -> O -> P -> S -> D 
... 
path n: ... 

Ho provato Codeviz e Doxygen, in qualche modo entrambi i risultati mostrano solo callees di funzione target, D. Nel mio caso, D è una funzione membro di una classe cui oggetto sarà spostato all'interno di una smart puntatore. I clienti otterranno sempre l'oggetto puntatore intelligente attraverso una fabbrica per invocare D.

Qualcuno sa come ottenere ciò?

risposta

95
static void D() { } 
static void Y() { D(); } 
static void X() { Y(); } 
static void C() { D(); X(); } 
static void B() { C(); } 
static void S() { D(); } 
static void P() { S(); } 
static void O() { P(); } 
static void N() { O(); } 
static void M() { N(); } 
static void G() { M(); } 
static void A() { B(); G(); } 

int main() { 
    A(); 
} 

Poi

$ clang++ -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph 
$ dot -Tpng -ocallgraph.png callgraph.dot 

ottengono circa immagine lucido (c'è un "nodo esterno", perché main ha linkage esterno e potrebbero essere definiti da fuori di tale unità Traduzione troppo):

Callgraph

Si consiglia di postelaborare questo con c++filt, in modo che è possibile ottenere i nomi unscangled di e funzioni e classi coinvolte. Come nel seguente

#include <vector> 

struct A { 
    A(int); 
    void f(); // not defined, prevents inlining it! 
}; 

int main() { 
    std::vector<A> v; 
    v.push_back(42); 
    v[0].f(); 
} 

$ clang++ -S -emit-llvm main1.cpp -o - | 
    opt -analyze -std-link-opts -dot-callgraph 
$ cat callgraph.dot | 
    c++filt | 
    sed 's,>,\\>,g; s,-\\>,->,g; s,<,\\<,g' | 
    gawk '/external node/{id=$1} $1 != id' | 
    dot -Tpng -ocallgraph.png  

rese questa bellezza (oh mio Dio, la dimensione senza ottimizzazioni acceso era troppo grande!)

Beauty

Che mistica funzione senza nome, Node0x884c4e0, è un segnaposto assunta essere chiamato da qualsiasi funzione la cui definizione non è nota.

+17

ci hai fatto questo su un progetto pluriennale di file? sembra molto bello come strumento – dirvine

+0

Esiste un modo per fare in modo che le funzioni che non sono locali al file/file come tutte le funzioni std che si chiamano non vengano chiamate? – soandos

+2

+1 Per qualche motivo ho dovuto passare l'opzione -n ​​a C++ filt affinché i nomi venissero sbrogliati. Ho pensato di parlarne qui nel caso in cui qualcun altro dovesse affrontare lo stesso problema. – Aky

3

Calcolare in modo statico un grafico di chiamata C++ accurato è difficile, perché è necessario un parser preciso per langauge, una corretta ricerca del nome e un buon analizzatore di punti che rispetta correttamente la semantica del linguaggio. Doxygen non ha nessuno di questi, non so perché la gente pretenda di apprezzarlo per il C++; è facile costruire un esempio di C++ a 10 righe che Doxygen analizza erroneamente).

Potrebbe essere meglio eseguire un timing profiler which collects a call graph dynamically (questo descrive il nostro) e semplicemente esercitare un sacco di casi. Tali profiler ti mostreranno l'effettivo grafo delle chiamate esercitato.

MODIFICA: Ho improvvisamente ricordato Understand for C++, che afferma di costruire grafici di chiamata. Non so cosa usano per un parser, o se eseguono correttamente l'analisi dettagliata; Non ho esperienza specifica con il loro prodotto.

Sono impressionato dalla risposta di Schaub, usando Clang; Mi aspetterei che Clang abbia tutti gli elementi giusti.

+0

Purtroppo non sono a conoscenza di tutti i casi d'uso che potrebbero scatenare tale funzione :(. In effetti, il mio obiettivo finale è quello di trovare l'elenco esatto dei casi d'uso che utilizzano tale funzione per scopi di debug.Sono in grado di trovare i chiamanti diretti con lo strumento di indicizzazione del codice, ma ho bisogno di capire tutti i percorsi di esecuzione per ulteriori analisi. – shiouming

3

Affinché il comando clang++ per trovare i file di intestazione standard come mpi.h due opzioni aggiuntive dovrebbero essere utilizzati -### -fsyntax-only, vale a dire il comando completo dovrebbe apparire come:

clang++ -### -fsyntax-only -S -emit-llvm main1.cpp -o - | opt -analyze -dot-callgraph 
1

La "C++ Bsc Analyzer" in grado di visualizzare chiamare i grafici - leggendo il file generato dall'utilità bscmake.

11

È possibile ottenere ciò utilizzando doxygen (con l'opzione di utilizzare punti per la generazione di grafici).

enter image description here

Con Johannes Schaub - litb main.cpp, esso genera questo:

enter image description here

doxygen/dot sono probabilmente più facile che clang/opt da installare ed eseguire. Non sono riuscito a installarlo da solo ed è per questo che ho cercato di trovare una soluzione alternativa!

+1

Potresti aggiungere un esempio di come eseguire doxygen per ottenere la finestra che hai incluso? –

+0

@nimble_ninja: lo screenshot della finestra di configurazione di doxywizard non è sufficiente? – jpo38

+0

Non sapevo che fosse da doxywizard. Grazie! –

3

Si può usare CppDepend, può genera molti tipi di grafici

  • Dipendenza Grafico
  • chiamata Grafico
  • di ereditarietà di classe Graph
  • Coupling Grafico
  • Percorso Grafico
  • Tutti i percorsi Grafico
  • Grafico del ciclo

enter image description here

Problemi correlati