Metode analisis dinamis
Di sini saya menjelaskan beberapa metode analisis dinamis.
Metode dinamis sebenarnya menjalankan program untuk menentukan grafik panggilan.
Kebalikan dari metode dinamis adalah metode statis, yang mencoba menentukannya dari sumber saja tanpa menjalankan program.
Keuntungan metode dinamis:
- menangkap pointer fungsi dan panggilan C ++ virtual. Ini ada dalam jumlah besar di perangkat lunak non-sepele.
Kekurangan metode dinamis:
- Anda harus menjalankan program, yang mungkin lambat, atau memerlukan pengaturan yang tidak Anda miliki, misalnya kompilasi silang
- hanya fungsi yang benar-benar dipanggil yang akan ditampilkan. Misalnya, beberapa fungsi dapat dipanggil atau tidak, bergantung pada argumen baris perintah.
KcacheGrind
https://kcachegrind.github.io/html/Home.html
Program tes:
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;
}
Pemakaian:
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
Anda sekarang tertinggal di dalam program GUI yang luar biasa yang berisi banyak data kinerja yang menarik.
Di kanan bawah, pilih tab "Grafik panggilan". Ini menunjukkan grafik panggilan interaktif yang berkorelasi dengan metrik kinerja di jendela lain saat Anda mengeklik fungsi.
Untuk mengekspor grafik, klik kanan dan pilih "Export Graph". PNG yang diekspor terlihat seperti ini:
Dari situ kita dapat melihat bahwa:
- node root adalah
_start
, yang merupakan titik masuk ELF sebenarnya, dan berisi boilerplate inisialisasi glibc
f0
, f1
dan f2
dipanggil seperti yang diharapkan dari satu sama lain
pointed
juga ditampilkan, meskipun kami memanggilnya dengan penunjuk fungsi. Ini mungkin tidak akan dipanggil jika kita telah memberikan argumen baris perintah.
not_called
tidak ditampilkan karena tidak dipanggil saat proses, karena kami tidak meneruskan argumen baris perintah tambahan.
Hal yang keren tentang itu valgrind
adalah tidak memerlukan opsi kompilasi khusus.
Oleh karena itu, Anda dapat menggunakannya bahkan jika Anda tidak memiliki kode sumber, hanya yang dapat dieksekusi.
valgrind
berhasil melakukannya dengan menjalankan kode Anda melalui "mesin virtual" yang ringan. Ini juga membuat eksekusi menjadi sangat lambat dibandingkan dengan eksekusi asli.
Seperti yang dapat dilihat pada grafik, informasi pengaturan waktu tentang setiap pemanggilan fungsi juga diperoleh, dan ini dapat digunakan untuk membuat profil program, yang kemungkinan merupakan kasus penggunaan asli dari pengaturan ini, tidak hanya untuk melihat grafik panggilan: Bagaimana saya dapat membuat profil Kode C ++ berjalan di Linux?
Diuji di Ubuntu 18.04.
gcc -finstrument-functions
+ etrace
https://github.com/elcritch/etrace
-finstrument-functions
menambahkan callback , etrace mem-parsing file ELF dan mengimplementasikan semua callback.
Sayangnya, saya tidak bisa membuatnya berfungsi: Mengapa `-finstrument-functions` tidak berfungsi untuk saya?
Output yang diklaim dalam 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
Mungkin metode yang paling efisien selain dukungan penelusuran perangkat keras tertentu, tetapi memiliki sisi negatif bahwa Anda harus mengkompilasi ulang kode.