Narzędzia do uzyskania graficznego wykresu wywołania funkcji kodu [zamknięte]


107

Mam dużą przestrzeń roboczą, która zawiera wiele plików źródłowych kodu C. Chociaż widzę funkcje wywoływane z funkcji w MS VS2005 przy użyciu przeglądarki obiektów, a także w MSVC 6.0, to pokazuje tylko funkcje wywoływane z określonej funkcji w nie-graficznym rodzaju wyświetlania. Ponadto nie pokazuje funkcji wywoływanej zaczynając od powiedzmy main(), a następnie funkcji wywoływanych z niej i tak dalej, w głąb funkcji na poziomie liścia.

Potrzebuję narzędzia, które da mi obrazowy wykres wywołań funkcji z funkcjami calleei callerpołączony strzałkami lub czymś w tym rodzaju, zaczynając od main()ostatniego poziomu funkcji lub przynajmniej przedstawiający graficznie wykres wywołań wszystkich funkcji w jednym pliku źródłowym C. Byłoby wspaniale, gdybym mógł wydrukować ten wykres.

Jakieś dobre narzędzia do tego (nie muszą to być darmowe narzędzia)?


Odpowiedzi:



29

Metody analizy dynamicznej

Tutaj opiszę kilka metod analizy dynamicznej.

Metody dynamiczne faktycznie uruchamiają program w celu określenia wykresu wywołania.

Przeciwieństwem metod dynamicznych są metody statyczne, które próbują określić je z samego źródła, bez uruchamiania programu.

Zalety metod dynamicznych:

  • przechwytuje wskaźniki funkcji i wirtualne wywołania C ++. Są one obecne w dużych ilościach w każdym nietrywialnym oprogramowaniu.

Wady metod dynamicznych:

  • musisz uruchomić program, który może być powolny lub wymagać instalacji, której nie masz, np. kompilacji krzyżowej
  • pokażą się tylko funkcje, które zostały faktycznie wywołane. Np. Niektóre funkcje można wywołać lub nie, w zależności od argumentów wiersza poleceń.

KcacheGrind

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

Program testowy:

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;
}

Stosowanie:

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

Jesteś teraz w niesamowitym programie GUI, który zawiera wiele interesujących danych dotyczących wydajności.

W prawym dolnym rogu wybierz kartę „Wykres połączeń”. Pokazuje interaktywny wykres wywołań, który jest skorelowany z metrykami wydajności w innych oknach po kliknięciu funkcji.

Aby wyeksportować wykres, kliknij go prawym przyciskiem myszy i wybierz „Eksportuj wykres”. Wyeksportowany plik PNG wygląda następująco:

Z tego widać, że:

  • węzeł główny to _start, który jest faktycznym punktem wejścia ELF i zawiera konfigurację standardową biblioteki glibc
  • f0, f1I f2są nazywane zgodnie z oczekiwaniami od siebie
  • pointedjest również wyświetlany, mimo że wywołaliśmy go wskaźnikiem funkcji. Mogłoby nie zostać wywołane, gdybyśmy przekazali argument wiersza poleceń.
  • not_called nie jest wyświetlany, ponieważ nie został wywołany w przebiegu, ponieważ nie przekazaliśmy dodatkowego argumentu wiersza poleceń.

Fajne valgrindjest to, że nie wymaga żadnych specjalnych opcji kompilacji.

Dlatego możesz go użyć, nawet jeśli nie masz kodu źródłowego, tylko plik wykonywalny.

valgrindudaje się to zrobić, uruchamiając kod za pośrednictwem lekkiej „maszyny wirtualnej”. Powoduje to również, że wykonywanie jest wyjątkowo wolne w porównaniu do wykonywania natywnego.

Jak widać na wykresie, uzyskiwane są również informacje o czasie każdego wywołania funkcji, które można wykorzystać do profilowania programu, co jest prawdopodobnie oryginalnym przypadkiem użycia tej konfiguracji, a nie tylko do wyświetlania wykresów połączeń: Jak mogę profilować Kod C ++ działający w systemie Linux?

Testowane na Ubuntu 18.04.

gcc -finstrument-functions + etrace

https://github.com/elcritch/etrace

-finstrument-functions dodaje wywołania zwrotne , etrace analizuje plik ELF i implementuje wszystkie wywołania zwrotne.

Niestety, nie udało mi się go uruchomić: Dlaczego `-finstrument-functions` nie działa dla mnie?

Zgłoszone dane wyjściowe mają format:

\-- 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

Prawdopodobnie najbardziej wydajna metoda poza obsługą specyficznego śledzenia sprzętu, ale ma tę wadę, że trzeba ponownie skompilować kod.


2
Zwróć uwagę, że dynamiczny wykres wywołań obejmuje tylko jedno uruchomienie programu.
smwikipedia

1
@smwikipedia tak, zaktualizowałem odpowiedź, aby była jaśniejsza
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功



9

Nasz DMS Software Reengineering Toolkit ma statyczną kontrolę / przepływ danych / analizę punktów do / wywołania , która została zastosowana w ogromnych systemach (~ ~ ~ 25 milionów linii) kodu C i stworzyła takie wykresy wywołań, w tym funkcje wywoływane za pomocą wskaźników funkcji .


1
Ach, fajnie, jest rok 2016 i teraz pojawia się zwolennik. Jestem pewien, że jego głos przeciwny wynikał z trafnej oceny, że to narzędzie nie może tego zrobić. Cóż, może nie. Z pewnością robi to, o co prosił OP.
Ira Baxter

1
Weź głos za, aby temu przeciwdziałać. Nie obchodzi mnie, że to twoje oprogramowanie lub własność, o ile wykonuje swoje zadanie :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功


5

Można sprawdzić moje C wywołania bash generator drzewo oparte tutaj . Pozwala określić jedną lub więcej funkcji C, dla których chcesz uzyskać informacje o dzwoniącym i / lub wywoływanym, lub możesz określić zestaw funkcji i określić wykres osiągalności wywołań funkcji, który je łączy ... To znaczy powiedz mi wszystkie sposoby main ( ), foo () i bar () są połączone. Używa graphviz / dot dla silnika graficznego.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.