Методи за динамичен анализ
Тук описвам няколко метода за динамичен анализ.
Динамичните методи всъщност изпълняват програмата, за да определят графиката на повикванията.
Обратното на динамичните методи са статичните методи, които се опитват да го определят само от източника, без да стартират програмата.
Предимства на динамичните методи:
- улавя указатели на функции и виртуални C++ извиквания. Те присъстват в голям брой във всеки нетривиален софтуер.
Недостатъци на динамичните методи:
- трябва да стартирате програмата, което може да е бавно или да изисква настройка, която нямате, напр. кръстосана компилация
- ще се показват само функциите, които действително са били извикани. Например, някои функции могат да бъдат извикани или не в зависимост от аргументите на командния ред.
KcacheGrind
https://kcachegrind.github.io/html/Home.html
Тестова програма:
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;
}
Употреба:
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
Сега сте оставени в една страхотна програма с GUI, която съдържа много интересни данни за производителността.
Долу вдясно изберете раздела „Графика на обажданията“. Това показва интерактивна графика на повикванията, която корелира с показателите за ефективност в други прозорци, докато щракнете върху функциите.
За да експортирате графиката, щракнете с десния бутон върху нея и изберете „Експортиране на графика“. Експортираният PNG изглежда така:
От това можем да видим, че:
- основният възел е
_start
, което е действителната входна точка на ELF и съдържа шаблон за инициализация на glibc
f0
, f1
и f2
се извикват както се очаква един от друг
pointed
също е показано, въпреки че го извикахме с указател на функция. Можеше да не бъде извикан, ако бяхме предали аргумент от командния ред.
not_called
не се показва, защото не е извикан при изпълнение, защото не сме предали допълнителен аргумент на командния ред.
Готиното при valgrind
е, че не изисква специални опции за компилиране.
Следователно можете да го използвате дори ако нямате изходния код, а само изпълнимия файл.
valgrind
успява да направи това, като стартира вашия код през лека "виртуална машина". Това също така прави изпълнението изключително бавно в сравнение с естественото изпълнение.
Както може да се види на графиката, информация за времето за всяко извикване на функция също се получава и това може да се използва за профилиране на програмата, което вероятно е първоначалният случай на използване на тази настройка, а не само за да видите графики на извикванията: Как мога да профилирам C++ код, работещ на Linux?
Тествано на Ubuntu 18.04.
gcc -finstrument-functions
+ etrace
https://github.com/elcritch/etrace
-finstrument-functions
добавя обратни извиквания, etrace анализира ELF файла и прилага всички обратни извиквания.
За съжаление обаче не можах да го накарам да работи: Защо не `-finstrument- функции работят за мен?
Заявеният изход е във формат:
\-- 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
Вероятно най-ефективният метод освен поддръжката за специфично проследяване на хардуер, но има недостатъка, че трябва да компилирате отново кода.
person
Ciro Santilli 新疆再教育营六四事件ۍ
schedule
02.07.2015