Strumenti per ottenere un grafico di chiamata di funzione pittorica del codice [chiuso]


107

Ho un ampio spazio di lavoro che ha molti file sorgente di codice C. Anche se posso vedere le funzioni chiamate da una funzione in MS VS2005 utilizzando il browser degli oggetti e anche in MSVC 6.0, questo mostra solo le funzioni chiamate da una particolare funzione in un tipo di visualizzazione non grafico. Inoltre, non mostra la funzione chiamata a partire da say main(), e quindi le funzioni chiamate da essa, e così via, più in profondità all'interno della funzione a livello foglia.

Ho bisogno di uno strumento che mi fornisca un grafico delle chiamate di funzione in modo pittorico con funzioni calleee callercollegato da frecce o qualcosa del genere, a partire main()dall'ultimo livello di funzione, o almeno che mostri un grafico delle chiamate di tutte le funzioni in un file sorgente C. Sarebbe fantastico se potessi stampare questo grafico.

Qualche buon strumento per farlo (non è necessario che sia gratuito)?


Risposte:



29

Metodi di analisi dinamica

Qui descrivo alcuni metodi di analisi dinamica.

I metodi dinamici eseguono effettivamente il programma per determinare il grafico delle chiamate.

L'opposto dei metodi dinamici sono metodi statici, che tentano di determinarlo solo dall'origine senza eseguire il programma.

Vantaggi dei metodi dinamici:

  • cattura i puntatori a funzioni e le chiamate virtuali C ++. Questi sono presenti in gran numero in qualsiasi software non banale.

Svantaggi dei metodi dinamici:

  • devi eseguire il programma, che potrebbe essere lento o richiedere una configurazione che non hai, ad esempio la compilazione incrociata
  • verranno visualizzate solo le funzioni che sono state effettivamente chiamate. Ad esempio, alcune funzioni potrebbero essere chiamate o meno a seconda degli argomenti della riga di comando.

KCachegrind

https://kcachegrind.github.io/html/Home.html

Programma di prova:

int f2(int i) { return i + 2; }
int f1(int i) { return f2(2) + i + 1; }
int f0(int i) { return f1(1) + f2(2); }
int pointed(int i) { return i; }
int not_called(int i) { return 0; }

int main(int argc, char **argv) {
    int (*f)(int);
    f0(1);
    f1(1);
    f = pointed;
    if (argc == 1)
        f(1);
    if (argc == 2)
        not_called(1);
    return 0;
}

Uso:

sudo apt-get install -y kcachegrind valgrind

# Compile the program as usual, no special flags.
gcc -ggdb3 -O0 -o main -std=c99 main.c

# Generate a callgrind.out.<PID> file.
valgrind --tool=callgrind ./main

# Open a GUI tool to visualize callgrind data.
kcachegrind callgrind.out.1234

Ora sei lasciato all'interno di un fantastico programma GUI che contiene molti dati interessanti sulle prestazioni.

In basso a destra, seleziona la scheda "Grafico chiamate". Questo mostra un grafico di chiamata interattivo correlato alle metriche delle prestazioni in altre finestre mentre fai clic sulle funzioni.

Per esportare il grafico, fare clic con il pulsante destro del mouse e selezionare "Esporta grafico". Il PNG esportato ha questo aspetto:

Da ciò possiamo vedere che:

  • il nodo radice è _start, che è l'effettivo punto di ingresso ELF, e contiene boilerplate di inizializzazione glibc
  • f0, f1E f2sono chiamati come previsto l'uno dall'altro
  • pointedviene mostrato anche, anche se l'abbiamo chiamato con un puntatore a funzione. Potrebbe non essere stato chiamato se avessimo passato un argomento della riga di comando.
  • not_called non viene mostrato perché non è stato chiamato durante l'esecuzione, perché non abbiamo passato un argomento aggiuntivo della riga di comando.

La cosa interessante valgrindè che non richiede alcuna speciale opzione di compilazione.

Pertanto, potresti usarlo anche se non hai il codice sorgente, solo l'eseguibile.

valgrindriesce a farlo eseguendo il codice attraverso una "macchina virtuale" leggera. Ciò rende anche l'esecuzione estremamente lenta rispetto all'esecuzione nativa.

Come si può vedere nel grafico, si ottengono anche informazioni sulla temporizzazione su ciascuna chiamata di funzione, che possono essere utilizzate per profilare il programma, che è probabilmente il caso d'uso originale di questa configurazione, non solo per vedere i grafici delle chiamate: Come posso profilare Codice C ++ in esecuzione su Linux?

Testato su Ubuntu 18.04.

gcc -finstrument-functions + etrace

https://github.com/elcritch/etrace

-finstrument-functions aggiunge callback , etrace analizza il file ELF e implementa tutti i callback.

Purtroppo non sono riuscito a farlo funzionare: Perché `-finstrument-functions` non funziona per me?

L'output dichiarato è nel formato:

\-- main
|   \-- Crumble_make_apple_crumble
|   |   \-- Crumble_buy_stuff
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   |   \-- Crumble_buy
|   |   \-- Crumble_prepare_apples
|   |   |   \-- Crumble_skin_and_dice
|   |   \-- Crumble_mix
|   |   \-- Crumble_finalize
|   |   |   \-- Crumble_put
|   |   |   \-- Crumble_put
|   |   \-- Crumble_cook
|   |   |   \-- Crumble_put
|   |   |   \-- Crumble_bake

Probabilmente il metodo più efficiente oltre al supporto di tracciamento hardware specifico, ma ha lo svantaggio di dover ricompilare il codice.


2
Basta notare che il grafico delle chiamate dinamiche copre solo un'esecuzione del programma.
smwikipedia

1
@smwikipedia sì, ho aggiornato la risposta per renderlo più chiaro
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功



9

Il nostro DMS Software Reengineering Toolkit ha analisi statiche di controllo / flusso di dati / punti a / chiamate che sono state applicate a sistemi enormi (~~ 25 milioni di righe) di codice C e hanno prodotto tali grafici di chiamata, comprese le funzioni chiamate tramite puntatori a funzione .


1
Ah, bello, è il 2016 e ora si presenta un downvoter. Sono sicuro che il suo voto negativo era basato su una valutazione accurata che questo strumento non può farlo. Beh, forse no. Sicuramente fa ciò che OP ha richiesto.
Ira Baxter

1
Prendi un voto positivo per contrastarlo. Non mi interessa che sia il tuo software o proprietario fintanto che fa il lavoro :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功


5

Puoi controllare il mio generatore di albero di chiamate C basato su bash qui . Ti consente di specificare una o più funzioni C per le quali desideri informazioni sul chiamante e / o chiamate, oppure puoi specificare un insieme di funzioni e determinare il grafico di raggiungibilità delle chiamate di funzione che le collega ... Cioè dimmi tutti i modi principali ( ), foo () e bar () sono collegati. Usa graphviz / dot per un motore grafico.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.