Bagaimana saya bisa profil kode C ++ berjalan di Linux?
1816
Saya memiliki aplikasi C ++, berjalan di Linux, yang sedang saya optimalkan. Bagaimana saya bisa menentukan area mana dari kode saya yang berjalan lambat?
Jika Anda akan memberikan lebih banyak data tentang tumpukan pengembangan Anda, Anda mungkin mendapatkan jawaban yang lebih baik. Ada profiler dari Intel dan Sun tetapi Anda harus menggunakan kompiler mereka. Apakah itu pilihan?
Sebagian besar jawabannya adalah codeprofiler. Namun, inversi prioritas, alias cache, pertentangan sumber daya, dll. Semuanya dapat menjadi faktor dalam mengoptimalkan dan kinerja. Saya pikir orang membaca informasi ke dalam kode lambat saya . FAQ sedang mereferensikan utas ini.
Saya biasa menggunakan pstack secara acak, sebagian besar waktu akan mencetak tumpukan paling khas di mana program sebagian besar waktu, maka menunjuk ke bottleneck.
Jose Manuel Gomez Alvarez
Jawaban:
1406
Jika tujuan Anda adalah menggunakan profiler, gunakan salah satu yang disarankan.
Namun, jika Anda sedang terburu-buru dan Anda dapat secara manual menginterupsi program Anda di bawah debugger ketika sedang lambat, ada cara sederhana untuk menemukan masalah kinerja.
Hentikan beberapa kali, dan setiap kali lihat tumpukan panggilan. Jika ada beberapa kode yang membuang-buang persentase waktu, 20% atau 50% atau apa pun, itu adalah probabilitas bahwa Anda akan menangkapnya dalam tindakan pada setiap sampel. Jadi, kira-kira persentase sampel yang Anda akan melihatnya. Tidak ada dugaan yang berpendidikan. Jika Anda memiliki dugaan tentang apa masalahnya, ini akan membuktikan atau membantahnya.
Anda mungkin memiliki beberapa masalah kinerja berbagai ukuran. Jika Anda membersihkan salah satu dari mereka, yang tersisa akan mengambil persentase lebih besar, dan lebih mudah dikenali, pada lintasan selanjutnya. Efek pembesaran ini , ketika diperparah dengan berbagai masalah, dapat menyebabkan faktor percepatan yang sangat besar.
Peringatan : Pemrogram cenderung skeptis terhadap teknik ini kecuali mereka telah menggunakannya sendiri. Mereka akan mengatakan bahwa profiler memberi Anda informasi ini, tetapi itu hanya benar jika mereka mencicipi seluruh tumpukan panggilan, dan kemudian membiarkan Anda memeriksa satu set sampel acak. (Ringkasan adalah tempat wawasan hilang.) Grafik panggilan tidak memberi Anda informasi yang sama, karena
Mereka tidak merangkum pada tingkat instruksi, dan
Mereka memberikan ringkasan yang membingungkan di hadapan rekursi.
Mereka juga akan mengatakan itu hanya bekerja pada program mainan, ketika sebenarnya itu bekerja pada program apa pun, dan tampaknya bekerja lebih baik pada program yang lebih besar, karena mereka cenderung memiliki lebih banyak masalah untuk ditemukan. Mereka akan mengatakan itu kadang-kadang menemukan hal-hal yang tidak masalah, tetapi itu hanya benar jika Anda melihat sesuatu sekali . Jika Anda melihat masalah pada lebih dari satu sampel, itu nyata.
PS Ini juga dapat dilakukan pada program multi-utas jika ada cara untuk mengumpulkan sampel panggilan-tumpukan dari kumpulan utas pada suatu titik waktu, seperti yang ada di Jawa.
PPS Sebagai generalitas kasar, semakin banyak lapisan abstraksi yang Anda miliki dalam perangkat lunak Anda, semakin besar kemungkinan Anda akan menemukan bahwa itu adalah penyebab masalah kinerja (dan peluang untuk mendapatkan peningkatan kecepatan).
Ditambahkan : Ini mungkin tidak jelas, tetapi teknik stack sampling bekerja sama baiknya di hadapan rekursi. Alasannya adalah bahwa waktu yang akan disimpan dengan menghapus instruksi diperkirakan oleh fraksi sampel yang mengandungnya, terlepas dari berapa kali itu dapat terjadi dalam sampel.
Keberatan lain yang sering saya dengar adalah: " Ini akan berhenti di suatu tempat secara acak, dan itu akan kehilangan masalah sebenarnya ". Ini berasal dari memiliki konsep sebelumnya tentang apa masalah sebenarnya. Properti utama dari masalah kinerja adalah bahwa mereka menentang harapan. Sampling memberi tahu Anda bahwa ada masalah, dan reaksi pertama Anda adalah tidak percaya. Itu wajar, tetapi Anda bisa yakin jika menemukan masalah itu nyata, dan sebaliknya.
Ditambahkan : Biarkan saya membuat penjelasan Bayesian tentang cara kerjanya. Misalkan ada beberapa instruksi I(panggilan atau lainnya) yang ada di panggilan menumpuk sebagian fwaktu (dan dengan demikian biaya yang banyak). Untuk kesederhanaan, anggaplah kita tidak tahu apa fitu, tetapi anggaplah itu adalah 0,1, 0,2, 0,3, ... 0,9, 1,0, dan probabilitas sebelumnya dari masing-masing kemungkinan ini adalah 0,1, sehingga semua biaya ini kemungkinan sama besarnya a-priori.
Kemudian anggaplah kita mengambil hanya 2 tumpukan sampel, dan kita melihat instruksi Ipada kedua sampel, pengamatan yang ditunjuk o=2/2. Ini memberi kita perkiraan baru dari frekuensi fdari I, menurut ini:
Prior
P(f=x) x P(o=2/2|f=x) P(o=2/2&&f=x) P(o=2/2&&f >= x) P(f >= x | o=2/2)0.1110.10.10.259740260.10.90.810.0810.1810.470129870.10.80.640.0640.2450.6363636360.10.70.490.0490.2940.7636363640.10.60.360.0360.330.8571428570.10.50.250.0250.3550.9220779220.10.40.160.0160.3710.9636363640.10.30.090.0090.380.9870129870.10.20.040.0040.3840.9974025970.10.10.010.0010.3851
P(o=2/2)0.385
Kolom terakhir mengatakan bahwa, misalnya, probabilitas bahwa f> = 0,5 adalah 92%, naik dari asumsi sebelumnya sebesar 60%.
Misalkan asumsi sebelumnya berbeda. Misalkan kita anggap P(f=0.1)0,991 (hampir pasti), dan semua kemungkinan lain hampir tidak mungkin (0,001). Dengan kata lain, kepastian kami sebelumnya adalah yang Imurah. Lalu kita dapatkan:
Prior
P(f=x) x P(o=2/2|f=x) P(o=2/2&& f=x) P(o=2/2&&f >= x) P(f >= x | o=2/2)0.001110.0010.0010.0727272730.0010.90.810.000810.001810.1316363640.0010.80.640.000640.002450.1781818180.0010.70.490.000490.002940.2138181820.0010.60.360.000360.00330.240.0010.50.250.000250.003550.2581818180.0010.40.160.000160.003710.2698181820.0010.30.090.000090.00380.2763636360.0010.20.040.000040.003840.2792727270.9910.10.010.009910.013751
P(o=2/2)0.01375
Sekarang dikatakan P(f >= 0.5)26%, naik dari asumsi sebelumnya 0,6%. Jadi Bayes memungkinkan kami memperbarui perkiraan biaya yang mungkin terjadi I. Jika jumlah data kecil, itu tidak memberi tahu kami secara akurat berapa biayanya, hanya bahwa itu cukup besar untuk diperbaiki.
Namun cara lain untuk melihatnya disebut Aturan Suksesi . Jika Anda melempar koin 2 kali, dan muncul dua kali di kepala, apa artinya itu memberi tahu Anda tentang kemungkinan bobot koin? Cara yang dihormati untuk menjawab adalah dengan mengatakan bahwa itu adalah distribusi Beta, dengan nilai rata-rata (number of hits + 1) / (number of tries + 2) = (2+1)/(2+2) = 75%.
(Kuncinya adalah bahwa kita melihat Ilebih dari sekali. Jika kita hanya melihatnya sekali, itu tidak memberi tahu kita banyak kecuali bahwa f> 0.)
Jadi, bahkan sejumlah kecil sampel dapat memberi tahu kami banyak tentang biaya instruksi yang dilihatnya. (Dan itu akan melihat mereka dengan frekuensi, rata-rata, sebanding dengan biaya mereka. Jika nsampel yang diambil, dan fbiaya, maka Iakan muncul di nf+/-sqrt(nf(1-f))sampel. Contoh, n=10, f=0.3, yang 3+/-1.4sampel.)
Ditambahkan : Untuk memberikan nuansa intuitif untuk perbedaan antara pengukuran dan pengambilan sampel tumpukan acak:
Ada profiler sekarang yang mengambil sampel tumpukan, bahkan pada waktu jam dinding, tetapi yang keluar adalah pengukuran (atau jalur panas, atau hot spot, dari mana "bottleneck" dapat dengan mudah disembunyikan). Apa yang mereka tidak perlihatkan kepada Anda (dan mereka dengan mudah bisa) adalah sampel yang sebenarnya. Dan jika tujuan Anda adalah menemukan kemacetan, jumlah yang perlu Anda lihat adalah, rata-rata , 2 dibagi dengan sebagian kecil dari waktu yang dibutuhkan. Jadi jika dibutuhkan 30% waktu, 2 / 0,3 = 6,7 sampel, rata-rata, akan menunjukkannya, dan kemungkinan 20 sampel akan menunjukkan itu adalah 99,2%.
Berikut ini adalah ilustrasi off-the-cuff perbedaan antara memeriksa pengukuran dan memeriksa sampel tumpukan. Kemacetan bisa jadi satu gumpalan besar seperti ini, atau banyak gumpalan kecil, tidak ada bedanya.
Pengukuran horisontal; ia memberi tahu Anda berapa lama waktu yang dibutuhkan untuk rutinitas khusus. Pengambilan sampel adalah vertikal. Jika ada cara untuk menghindari apa yang dilakukan seluruh program pada saat itu, dan jika Anda melihatnya pada sampel kedua , Anda telah menemukan hambatannya. Itulah yang membuat perbedaan - melihat seluruh alasan waktu yang dihabiskan, bukan hanya berapa banyak.
Ini pada dasarnya adalah profiler pengambilan sampel orang miskin, yang bagus, tetapi Anda berisiko mengambil ukuran sampel terlalu kecil yang mungkin akan memberi Anda hasil yang sepenuhnya palsu.
Crashworks
100
@ Crash: Saya tidak akan memperdebatkan bagian "orang miskin" :-) Memang benar bahwa pengukuran presisi statistik membutuhkan banyak sampel, tetapi ada dua tujuan yang saling bertentangan - pengukuran dan lokasi masalah. Saya fokus pada yang terakhir, yang Anda butuhkan ketepatan lokasi, bukan ketepatan ukuran. Jadi misalnya, mungkin ada, tumpukan tengah, panggilan fungsi tunggal A (); yang menyumbang 50% dari waktu, tetapi bisa dalam fungsi besar B lainnya, bersama dengan banyak panggilan lain ke A () yang tidak mahal. Ringkasan waktu fungsi yang tepat bisa menjadi petunjuk, tetapi setiap sampel tumpukan lainnya akan menunjukkan masalah.
Mike Dunlavey
41
... dunia tampaknya berpikir bahwa grafik panggilan, yang dianotasi dengan jumlah panggilan dan / atau waktu rata-rata, cukup baik. Bukan itu. Dan bagian yang menyedihkan adalah, bagi mereka yang mencicipi tumpukan panggilan, informasi yang paling berguna tepat di depan mereka, tetapi mereka membuangnya, demi "statistik".
Mike Dunlavey
30
Saya tidak bermaksud untuk tidak setuju dengan teknik Anda. Jelas saya sangat mengandalkan profiler sampling stack-walking. Saya hanya menunjukkan bahwa ada beberapa alat yang melakukannya secara otomatis sekarang, yang penting ketika Anda melewati titik mendapatkan fungsi dari 25% hingga 15% dan perlu merobohkannya dari 1,2% menjadi 0,6%.
Crashworks
13
-1: Ide bagus, tetapi jika Anda dibayar untuk bekerja di lingkungan yang berorientasi kinerja sekalipun, ini adalah buang-buang waktu semua orang. Gunakan profiler asli sehingga kami tidak perlu ikut serta dan memperbaiki masalah yang sebenarnya.
Sam Harwell
583
Anda dapat menggunakan Valgrind dengan opsi berikut
valgrind --tool=callgrind ./(Your binary)
Ini akan menghasilkan file bernama callgrind.out.x. Anda kemudian dapat menggunakan kcachegrindalat untuk membaca file ini. Ini akan memberi Anda analisis grafis dari hal-hal dengan hasil seperti garis mana yang menghabiskan biaya.
Valgrind besar, tetapi memperingatkan bahwa hal itu akan membuat sialan program anda lambat
Neves
30
Lihat juga Gprof2Dot untuk cara alternatif yang menakjubkan untuk memvisualisasikan output. ./gprof2dot.py -f callgrind callgrind.out.x | dot -Tsvg -o output.svg
Sebastian
2
@neves Ya Valgrind tidak begitu membantu dalam hal kecepatan untuk membuat profil aplikasi "gstreamer" dan "opencv" secara real-time.
Saya setuju bahwa gprof adalah standar saat ini. Sekadar catatan, Valgrind digunakan untuk kebocoran memori profil dan aspek terkait memori lainnya dari program Anda, bukan untuk optimasi kecepatan.
Bill the Lizard
68
Bill, Dalam paket vaglrind Anda dapat menemukan callgrind dan massif. Keduanya cukup berguna untuk aplikasi profil
gprof -pg hanya merupakan perkiraan profil panggilan balik. Ini menyisipkan panggilan mcount untuk melacak fungsi mana yang memanggil fungsi lain. Ini menggunakan pengambilan sampel berdasarkan waktu standar untuk, eh, waktu. Ini kemudian membagi kali sampel dalam suatu fungsi foo () kembali ke penelepon foo (), sesuai dengan jumlah panggilan. Jadi itu tidak membedakan antara panggilan biaya yang berbeda.
Krazy Glew
1
Dengan dentang / dentang ++, orang dapat mempertimbangkan untuk menggunakan profiler CPU gperftools . Peringatan: Belum melakukannya sendiri.
einpoklum
257
Kernel yang lebih baru (mis. Kernel Ubuntu terbaru) hadir dengan alat 'perf' baru ( apt-get install linux-tools) AKA perf_events .
Yang penting adalah bahwa alat-alat ini dapat berupa sistem profiling dan bukan hanya proses profiling - mereka dapat menunjukkan interaksi antara utas, proses dan kernel dan membiarkan Anda memahami penjadwalan dan dependensi I / O antara proses.
Alat hebat! Apakah ada cara bagi saya untuk mendapatkan tampilan "kupu-kupu" khas yang dimulai dari gaya "main-> func1-> fun2"? Sepertinya saya tidak bisa mengetahuinya ... perf reportsepertinya memberi saya nama fungsi dengan orang tua panggilan ... (jadi ini semacam tampilan kupu-kupu terbalik)
kizzx2
Will, dapat menampilkan timechart aktivitas utas; dengan informasi nomor CPU ditambahkan? Saya ingin melihat kapan dan utas mana yang berjalan pada setiap CPU.
osgx
2
@ kizzx2 - Anda dapat menggunakan gprof2dotdan perf script. Alat yang sangat bagus!
Pengantar bagus lainnya perfada di archive.li/9r927#selection-767.126-767.271 (Mengapa para dewa SO memutuskan untuk menghapus halaman itu dari basis pengetahuan SO adalah di luar saya ....)
ragerdl
75
Saya akan menggunakan Valgrind dan Callgrind sebagai dasar untuk rangkaian alat profiling saya. Yang penting diketahui adalah bahwa Valgrind pada dasarnya adalah Mesin Virtual:
(wikipedia) Valgrind pada dasarnya adalah mesin virtual yang menggunakan teknik kompilasi just-in-time (JIT), termasuk kompilasi dinamis. Tidak ada dari program asli yang dapat dijalankan langsung pada prosesor host. Sebagai gantinya, Valgrind pertama menerjemahkan program ke dalam bentuk sementara, lebih sederhana yang disebut Intermediate Representation (IR), yang merupakan bentuk netral-prosesor, berbasis SSA. Setelah konversi, alat (lihat di bawah) bebas untuk melakukan transformasi apa pun yang diinginkannya pada IR, sebelum Valgrind menerjemahkan kembali IR ke dalam kode mesin dan membiarkan prosesor host menjalankannya.
Callgrind adalah profiler yang dibangun di atas itu. Manfaat utama adalah Anda tidak perlu menjalankan aplikasi selama berjam-jam untuk mendapatkan hasil yang andal. Bahkan satu run kedua sudah cukup untuk mendapatkan hasil yang solid, andal, karena Callgrind adalah profiler non-probing .
Alat lain yang dibangun di atas Valgrind adalah Massif. Saya menggunakannya untuk penggunaan memori tumpukan profil. Ini bekerja dengan baik. Apa yang dilakukannya adalah memberi Anda snapshot dari penggunaan memori - informasi terperinci APA yang memegang persentase memori APA, dan WHO telah meletakkannya di sana. Informasi tersebut tersedia di berbagai titik waktu aplikasi dijalankan.
Jawaban untuk menjalankan valgrind --tool=callgrindtidak cukup lengkap tanpa beberapa opsi. Kami biasanya tidak ingin profil 10 menit waktu startup lambat di bawah Valgrind dan ingin profil program kami ketika sedang melakukan beberapa tugas.
Jadi ini yang saya rekomendasikan. Jalankan program terlebih dahulu:
Sekarang ketika ia berfungsi dan kami ingin memulai pembuatan profil, kami harus menjalankannya di jendela lain:
callgrind_control -i on
Ini mengaktifkan profil. Untuk mematikannya dan menghentikan seluruh tugas yang mungkin kita gunakan:
callgrind_control -k
Sekarang kami memiliki beberapa file bernama callgrind.out. * Di direktori saat ini. Untuk melihat hasil pembuatan profil, gunakan:
kcachegrind callgrind.out.*
Saya sarankan di jendela berikutnya untuk mengklik tajuk kolom "Cukup", jika tidak, ini menunjukkan bahwa "main ()" adalah tugas yang paling memakan waktu. "Diri" menunjukkan seberapa banyak masing-masing fungsi itu sendiri memakan waktu, tidak bersama-sama dengan tanggungan.
Sekarang dengan alasan tertentu file callgrind.out. * Selalu kosong. Menjalankan callgrind_control -d berguna untuk memaksa dump data ke disk.
Tõnu Samuel
3
Tidak bisa Konteks saya yang biasa adalah sesuatu seperti seluruh MySQL atau PHP atau hal besar serupa. Seringkali bahkan tidak tahu apa yang ingin saya pisahkan pada awalnya.
T Samuelnu Samuel
2
Atau dalam kasus saya, program saya sebenarnya memuat banyak data ke dalam cache LRU, dan saya ingin tidak membuat profil itu. Jadi saya paksa memuat subset cache saat startup, dan profil kode hanya menggunakan data itu (membiarkan OS + CPU mengelola penggunaan memori dalam cache saya). Ini bekerja, tetapi memuat cache itu lambat dan intensif CPU di seluruh kode yang saya coba profil dalam konteks yang berbeda, jadi callgrind menghasilkan hasil yang sangat tercemar.
Saya telah menggunakan Gprof beberapa hari terakhir dan telah menemukan tiga batasan signifikan, salah satunya saya belum melihat didokumentasikan di tempat lain (belum):
Itu tidak bekerja dengan baik pada kode multi-threaded, kecuali jika Anda menggunakan solusi
Grafik panggilan menjadi bingung oleh pointer fungsi. Contoh: Saya memiliki fungsi yang dipanggil multithread()yang memungkinkan saya untuk melakukan multi-utas fungsi yang ditentukan pada array yang ditentukan (keduanya dilewatkan sebagai argumen). Namun, lihat semua panggilan multithread()sebagai setara untuk keperluan menghitung waktu yang dihabiskan pada anak-anak. Karena beberapa fungsi yang saya multithread()anggap lebih lama dari yang lain, grafik panggilan saya sebagian besar tidak berguna. (Bagi mereka yang bertanya-tanya apakah threading adalah masalah di sini: tidak, multithread()bisa opsional, dan memang dalam hal ini, jalankan semuanya secara berurutan pada utas panggilan saja).
Dikatakan di sini bahwa "... jumlah angka panggilan diperoleh dengan menghitung, bukan pengambilan sampel. Angka tersebut sepenuhnya akurat ...". Namun saya menemukan grafik panggilan saya memberi saya 5345859132 + 784984078 sebagai statistik panggilan untuk fungsi saya yang paling dipanggil, di mana nomor pertama seharusnya menjadi panggilan langsung, dan panggilan rekursif kedua (yang semuanya dari dirinya sendiri). Karena ini tersirat saya punya bug, saya memasukkan penghitung panjang (64-bit) ke dalam kode dan melakukan hal yang sama lagi. Hitungan saya: 5345859132 langsung, dan 78094395406 panggilan rekursif diri. Ada banyak digit di sana, jadi saya akan menunjukkan panggilan rekursif yang saya ukur adalah 78bn, dibandingkan 784m dari Gprof: faktor 100 berbeda. Keduanya berjalan adalah kode berulir tunggal dan tidak dioptimalkan, satu dikompilasi -gdan yang lainnya -pg.
Ini adalah GNU Gprof (GNU Binutils for Debian) 2.18.0.20080103 berjalan di bawah Debian Lenny 64-bit, jika itu membantu siapa pun.
Ya, itu memang sampel, tetapi tidak untuk angka panggilan. Menariknya, mengikuti tautan Anda pada akhirnya membawa saya ke versi terbaru dari halaman buku panduan yang saya tautkan dalam posting saya, URL baru: sourceware.org/binutils/docs/gprof/… Ini mengulangi kutipan di bagian (iii) dari jawaban saya, tetapi juga mengatakan "Dalam aplikasi multi-utas, atau aplikasi utas tunggal yang ditautkan dengan pustaka multi-utas, penghitungan hanya deterministik jika fungsi penghitungan aman-thread. (Catatan: berhati-hatilah bahwa fungsi penghitungan mcount di glibc bukan thread -aman)."
Rob_before_edits
Tidak jelas bagi saya jika ini menjelaskan hasil saya di (iii). Kode saya ditautkan -lpthread -lm dan mendeklarasikan sebagai "pthread_t * thr" dan "pthread_mutex_t nextLock = PTHREAD_MUTEX_INITIALIZER" variabel statis bahkan ketika sedang menjalankan single threaded. Saya biasanya menganggap bahwa "tautan dengan perpustakaan multi-utas" berarti benar-benar menggunakan perpustakaan itu, dan pada tingkat yang lebih besar dari ini, tetapi saya bisa saja salah!
Rob_before_edits
23
Gunakan Valgrind, callgrind, dan kcachegrind:
valgrind --tool=callgrind ./(Your binary)
menghasilkan callgrind.out.x. Baca ini menggunakan kcachegrind.
Gunakan gprof (tambahkan -pg):
cc -o myprog myprog.c utils.c -g -pg
(tidak begitu baik untuk multi-utas, pointer fungsi)
Gunakan google-perftools:
Menggunakan sampling waktu, I / O dan kemacetan CPU terungkap.
Intel VTune adalah yang terbaik (gratis untuk tujuan pendidikan).
Lainnya: AMD Codeanalyst (sejak diganti dengan AMD CodeXL), OProfile, alat 'perf' (apt-get install linux-tools)
Dalam jawaban ini, saya akan menggunakan beberapa alat berbeda untuk menganalisis beberapa program pengujian yang sangat sederhana, untuk membandingkan secara konkret cara kerja alat tersebut.
Program pengujian berikut ini sangat sederhana dan melakukan hal berikut:
mainpanggilan fastdan maybe_slow3 kali, salah satu maybe_slowpanggilan menjadi lambat
Panggilan lambat maybe_slowadalah 10x lebih lama, dan mendominasi runtime jika kami mempertimbangkan panggilan ke fungsi anak common. Idealnya, alat profiling akan dapat mengarahkan kita ke panggilan lambat tertentu.
keduanya fastdan maybe_slowpanggilan common, yang menyumbang sebagian besar pelaksanaan program
Antarmuka program adalah:
./main.out [n [seed]]
dan program ini melakukan O(n^2)loop secara total. seedhanya untuk mendapatkan output yang berbeda tanpa mempengaruhi runtime.
main.c
#include<inttypes.h>#include<stdio.h>#include<stdlib.h>uint64_t __attribute__ ((noinline)) common(uint64_t n,uint64_t seed){for(uint64_t i =0; i < n;++i){
seed =(seed * seed)-(3* seed)+1;}return seed;}uint64_t __attribute__ ((noinline)) fast(uint64_t n,uint64_t seed){uint64_t max =(n /10)+1;for(uint64_t i =0; i < max;++i){
seed = common(n,(seed * seed)-(3* seed)+1);}return seed;}uint64_t __attribute__ ((noinline)) maybe_slow(uint64_t n,uint64_t seed,int is_slow){uint64_t max = n;if(is_slow){
max *=10;}for(uint64_t i =0; i < max;++i){
seed = common(n,(seed * seed)-(3* seed)+1);}return seed;}int main(int argc,char**argv){uint64_t n, seed;if(argc >1){
n = strtoll(argv[1], NULL,0);}else{
n =1;}if(argc >2){
seed = strtoll(argv[2], NULL,0);}else{
seed =0;}
seed += maybe_slow(n, seed,0);
seed += fast(n, seed);
seed += maybe_slow(n, seed,1);
seed += fast(n, seed);
seed += maybe_slow(n, seed,0);
seed += fast(n, seed);
printf("%" PRIX64 "\n", seed);return EXIT_SUCCESS;}
gprof
gprof membutuhkan kompilasi ulang perangkat lunak dengan instrumentasi, dan itu juga menggunakan pendekatan pengambilan sampel bersama dengan instrumentasi itu. Karena itu, ia menemukan keseimbangan antara akurasi (pengambilan sampel tidak selalu sepenuhnya akurat dan dapat melewati fungsi) dan pelambatan eksekusi (instrumentasi dan pengambilan sampel adalah teknik yang relatif cepat yang tidak terlalu memperlambat eksekusi).
gprof terintegrasi dengan GCC / binutils, jadi yang harus kita lakukan adalah mengkompilasi dengan -pgopsi untuk mengaktifkan gprof. Kami kemudian menjalankan program secara normal dengan parameter CLI ukuran yang menghasilkan jangka waktu yang wajar beberapa detik ( 10000):
Untuk alasan pendidikan, kami juga akan menjalankan tanpa mengaktifkan optimisasi. Perhatikan bahwa ini tidak berguna dalam praktik, karena Anda biasanya hanya peduli untuk mengoptimalkan kinerja program yang dioptimalkan:
Pertama, timeberi tahu kami bahwa waktu eksekusi dengan dan tanpa -pgsama, yang hebat: tidak ada perlambatan! Namun saya telah melihat akun perlambatan 2x - 3x pada perangkat lunak yang kompleks, misalnya seperti yang ditunjukkan dalam tiket ini .
Karena kami kompilasi dengan -pg, menjalankan program menghasilkan file gmon.outfile yang berisi data profil.
Di sini, gprofalat membaca gmon.outinformasi jejak, dan menghasilkan laporan yang dapat dibaca manusia main.gprof, yang gprof2dotkemudian dibaca untuk menghasilkan grafik.
The -O0output cukup banyak jelas. Sebagai contoh, ini menunjukkan bahwa 3 maybe_slowpanggilan dan panggilan anak mereka mengambil 97,56% dari total runtime, meskipun eksekusi maybe_slowitu sendiri tanpa anak-anak menyumbang 0,00% dari total waktu eksekusi, yaitu hampir semua waktu yang dihabiskan dalam fungsi tersebut dihabiskan untuk panggilan anak.
TODO: mengapa mainhilang dari -O3output, meskipun saya bisa melihatnya di btdalam GDB? Fungsi yang hilang dari keluaran GProf saya pikir itu karena gprof juga berdasarkan sampel selain instrumentasi yang dikompilasi, dan -O3mainterlalu cepat dan tidak punya sampel.
Saya memilih output SVG daripada PNG karena SVG dapat dicari dengan Ctrl + F dan ukuran file bisa sekitar 10x lebih kecil. Selain itu, lebar dan tinggi gambar yang dihasilkan dapat menjadi sangat muda dengan puluhan ribu piksel untuk perangkat lunak yang kompleks, dan eogbug GNOME 3.28.1 keluar dalam hal itu untuk PNG, sementara SVG dibuka oleh browser saya secara otomatis. gimp 2.8 bekerja dengan baik, lihat juga:
tetapi meskipun demikian, Anda akan banyak menyeret gambar di sekitar untuk menemukan apa yang Anda inginkan, lihat misalnya gambar ini dari contoh perangkat lunak "nyata" yang diambil dari tiket ini :
Dapatkah Anda menemukan tumpukan panggilan yang paling penting dengan mudah dengan semua garis spaghetti kecil yang tidak disortir saling bertabrakan? Mungkin ada dotopsi yang lebih baik saya yakin, tetapi saya tidak ingin pergi ke sana sekarang. Yang benar-benar kita butuhkan adalah pemirsa khusus yang berdedikasi untuk itu, tetapi saya belum menemukannya:
Namun Anda dapat menggunakan peta warna untuk sedikit mengurangi masalah tersebut. Misalnya, pada gambar besar sebelumnya, saya akhirnya berhasil menemukan jalur kritis di sebelah kiri ketika saya membuat deduksi cemerlang bahwa hijau muncul setelah merah, diikuti akhirnya dengan biru yang lebih gelap dan lebih gelap.
Atau, kita juga dapat mengamati keluaran teks dari gprofalat binutils bawaan yang sebelumnya kita simpan di:
cat main.gprof
Secara default, ini menghasilkan output yang sangat verbose yang menjelaskan apa artinya data output. Karena saya tidak bisa menjelaskan lebih baik dari itu, saya akan membiarkan Anda membacanya sendiri.
Setelah Anda memahami format output data, Anda dapat mengurangi verbositas untuk hanya menampilkan data tanpa tutorial dengan -bopsi:
gprof -b main.out
Dalam contoh kami, output untuk -O0:
Flat profile:Each sample counts as 0.01 seconds.% cumulative self self total
time seconds seconds calls s/call s/call name
100.353.673.671230030.000.00 common
0.003.670.0030.000.03 fast
0.003.670.0030.001.19 maybe_slow
Call graph
granularity: each sample hit covers 2 byte(s)for0.27% of 3.67 seconds
index % time self children called name
0.090.003003/123003 fast [4]3.580.00120000/123003 maybe_slow [3][1]100.03.670.00123003 common [1]-----------------------------------------------<spontaneous>[2]100.00.003.67 main [2]0.003.583/3 maybe_slow [3]0.000.093/3 fast [4]-----------------------------------------------0.003.583/3 main [2][3]97.60.003.583 maybe_slow [3]3.580.00120000/123003 common [1]-----------------------------------------------0.000.093/3 main [2][4]2.40.000.093 fast [4]0.090.003003/123003 common [1]-----------------------------------------------Index by function name
[1] common [4] fast [3] maybe_slow
dan untuk -O3:
Flat profile:Each sample counts as 0.01 seconds.% cumulative self self total
time seconds seconds calls us/call us/call name
100.521.841.8412300314.9614.96 common
Call graph
granularity: each sample hit covers 2 byte(s)for0.54% of 1.84 seconds
index % time self children called name
0.040.003003/123003 fast [3]1.790.00120000/123003 maybe_slow [2][1]100.01.840.00123003 common [1]-----------------------------------------------<spontaneous>[2]97.60.001.79 maybe_slow [2]1.790.00120000/123003 common [1]-----------------------------------------------<spontaneous>[3]2.40.000.04 fast [3]0.040.003003/123003 common [1]-----------------------------------------------Index by function name
[1] common
Sebagai ringkasan yang sangat cepat untuk setiap bagian, misalnya:
0.003.583/3 main [2][3]97.60.003.583 maybe_slow [3]3.580.00120000/123003 common [1]
berpusat di sekitar fungsi yang dibiarkan berlekuk ( maybe_flow). [3]adalah ID dari fungsi itu. Di atas fungsi, ada peneleponnya, dan di bawahnya ada callees.
Untuk -O3, lihat di sini seperti pada keluaran grafis itu maybe_slowdan fasttidak memiliki orangtua yang dikenal, yang merupakan arti dari dokumentasi itu <spontaneous>.
valgrind menjalankan program melalui mesin virtual valgrind. Ini membuat profil sangat akurat, tetapi juga menghasilkan perlambatan program yang sangat besar. Saya juga telah menyebutkan kcachegrind sebelumnya di: Alat untuk mendapatkan grafik panggilan fungsi bergambar kode
callgrind adalah alat valgrind untuk kode profil dan kcachegrind adalah program KDE yang dapat memvisualisasikan output cachegrind.
Pertama kita harus menghapus -pgflag untuk kembali ke kompilasi normal, jika tidak run sebenarnya gagal Profiling timer expired, dan ya, ini sangat umum yang saya lakukan dan ada pertanyaan Stack Overflow untuk itu.
Saya mengaktifkan --dump-instr=yes --collect-jumps=yeskarena ini juga membuang informasi yang memungkinkan kami melihat gangguan kinerja per jalur perakitan, dengan biaya overhead tambahan yang relatif kecil.
Off the bat, timememberitahu kami bahwa program ini membutuhkan waktu 29,5 detik untuk dieksekusi, jadi kami mengalami penurunan sekitar 15x pada contoh ini. Jelas, perlambatan ini akan menjadi batasan serius untuk beban kerja yang lebih besar. Pada "contoh perangkat lunak dunia nyata" yang disebutkan di sini , saya mengamati penurunan 80x.
Proses menghasilkan file data profil bernama callgrind.out.<pid>eg callgrind.out.8554dalam kasus saya. Kami melihat file itu dengan:
kcachegrind callgrind.out.8554
yang menunjukkan GUI yang berisi data yang mirip dengan output gprof tekstual:
Juga, jika kita pergi ke kanan bawah "Grafik Panggilan" tab, kita melihat grafik panggilan yang dapat kita ekspor dengan mengklik kanan untuk mendapatkan gambar berikut dengan jumlah batas putih yang tidak masuk akal :-)
Saya pikir fasttidak muncul pada grafik itu karena kcachegrind pasti telah menyederhanakan visualisasi karena panggilan itu memakan waktu terlalu sedikit, ini kemungkinan akan menjadi perilaku yang Anda inginkan pada program nyata. Menu klik kanan memiliki beberapa pengaturan untuk mengontrol kapan harus menyisihkan node seperti itu, tetapi saya tidak bisa membuatnya untuk menampilkan panggilan singkat setelah upaya cepat. Jika saya mengklik pada fastjendela kiri, itu memang menampilkan grafik panggilan fast, sehingga tumpukan itu benar-benar ditangkap. Belum ada yang menemukan cara untuk menampilkan grafik panggilan grafik lengkap: Buat panggilan panggil tunjukkan semua panggilan fungsi di kcachegrind callgraph
TODO pada perangkat lunak C ++ yang kompleks, saya melihat beberapa entri tipe <cycle N>, misalnya di <cycle 11>mana saya mengharapkan nama fungsi, apa artinya itu? Saya perhatikan ada tombol "Deteksi Siklus" untuk menghidupkan dan mematikannya, tetapi apa artinya?
perf dari linux-tools
perftampaknya menggunakan mekanisme pengambilan sampel kernel Linux secara eksklusif. Ini membuatnya sangat mudah untuk diatur, tetapi juga tidak sepenuhnya akurat.
sudo apt install linux-tools
time perf record -g ./main.out 10000
Ini menambahkan 0,2s ke eksekusi, jadi kami baik-baik saja waktu, tapi saya masih tidak melihat banyak minat, setelah memperluas commonnode dengan panah kanan keyboard:
Jadi saya mencoba membuat tolok ukur -O0program untuk melihat apakah itu menunjukkan sesuatu, dan hanya sekarang, akhirnya, saya melihat grafik panggilan:
TODO: apa yang terjadi pada -O3eksekusi? Apakah hanya itu maybe_slowdan fastterlalu cepat dan tidak mendapatkan sampel? Apakah ini bekerja dengan baik -O3pada program yang lebih besar yang membutuhkan waktu lebih lama untuk dijalankan? Apakah saya melewatkan beberapa opsi CLI? Saya menemukan tentang -Funtuk mengontrol frekuensi sampel dalam Hertz, tetapi saya mengubahnya hingga maks diizinkan secara default -F 39500(dapat ditingkatkan dengan sudo) dan saya masih tidak melihat panggilan yang jelas.
Satu hal keren tentang perfalat FlameGraph dari Brendan Gregg yang menampilkan pengaturan waktu panggilan dengan cara yang sangat rapi yang memungkinkan Anda untuk dengan cepat melihat panggilan besar. Alat ini tersedia di: https://github.com/brendangregg/FlameGraph dan juga disebutkan pada nya Perf tutorial di: http://www.brendangregg.com/perf.html#FlameGraphs Ketika aku berlari perftanpa sudoaku ERROR: No stack counts foundjadi untuk sekarang saya akan melakukannya dengan sudo:
tetapi dalam program sederhana seperti itu, keluarannya tidak mudah dipahami, karena kita tidak dapat dengan mudah melihat maybe_slowmaupun fastpada grafik itu:
Pada contoh yang lebih kompleks, menjadi jelas apa arti grafik:
TODO ada log [unknown]fungsi dalam contoh itu, mengapa begitu?
Antarmuka GUI perf lain yang mungkin layak termasuk:
Tetapi ini memiliki kelemahan yaitu Anda harus terlebih dahulu mengonversi data ke Format Jejak Umum, yang dapat dilakukan dengan perf data --to-ctf, tetapi harus diaktifkan pada waktu membangun / memiliki perfcukup baru, yang keduanya tidak berlaku untuk perf di Ubuntu 18.04
Kemudian, kita dapat mengaktifkan profiler CPU gperftools dalam dua cara: saat runtime, atau saat membangun.
Pada saat runtime, kita harus melewati set LD_PRELOADto point ke libprofiler.so, yang dapat Anda temukan locate libprofiler.so, misalnya di sistem saya:
Cara terbaik untuk melihat data ini yang saya temukan sejauh ini adalah membuat pprof output dalam format yang sama dengan yang diambil oleh kcachegrind sebagai input (ya, alat Valgrind-project-viewer-tool) dan gunakan kcachegrind untuk melihat bahwa:
Setelah berjalan dengan salah satu metode tersebut, kami mendapatkan prof.outfile data profil sebagai output. Kita dapat melihat file itu secara grafis sebagai SVG dengan:
google-pprof --web main.out prof.out
yang memberi sebagai grafik panggilan akrab seperti alat lain, tetapi dengan unit kikuk jumlah sampel daripada detik.
Atau, kita juga bisa mendapatkan beberapa data tekstual dengan:
google-pprof --text main.out prof.out
pemberian yang mana:
Using local file main.out.Using local file prof.out.Total:187 samples
187100.0%100.0%187100.0% common
00.0%100.0%187100.0% __libc_start_main
00.0%100.0%187100.0% _start
00.0%100.0%42.1% fast
00.0%100.0%187100.0% main
00.0%100.0%18397.9% maybe_slow
Secara default, perf record menggunakan register penunjuk bingkai. Kompiler modern tidak mencatat alamat bingkai dan sebaliknya menggunakan register sebagai tujuan umum. Alternatifnya adalah mengkompilasi dengan -fno-omit-frame-pointerflag atau menggunakan alternatif lain: merekam dengan --call-graph "dwarf"atau --call-graph "lbr"tergantung pada skenario Anda.
Jorge Bellon
5
Untuk program berulir tunggal, Anda dapat menggunakan igprof , The Ignominous Profiler: https://igprof.org/ .
Ini adalah profiler pengambilan sampel, di sepanjang baris ... panjang ... jawaban oleh Mike Dunlavey, yang akan membungkus hasil dalam susunan pohon panggilan yang dapat dijelajahi, dijelaskan dengan waktu atau memori yang dihabiskan di setiap fungsi, baik kumulatif atau per-fungsi.
Ini terlihat menarik, tetapi gagal dikompilasi dengan GCC 9.2. (Debian / Sid) Saya membuat masalah di github.
Basile Starynkevitch
5
Juga layak disebutkan
HPCToolkit ( http://hpctoolkit.org/ ) - Sumber terbuka, berfungsi untuk program paralel dan memiliki GUI yang dapat digunakan untuk melihat hasil dengan berbagai cara
Saya telah menggunakan HPCToolkit dan VTune dan mereka sangat efektif dalam menemukan kutub panjang di tenda dan tidak perlu kode Anda untuk dikompilasi ulang (kecuali bahwa Anda harus menggunakan tipe -g -O atau RelWithDebInfo di CMake untuk mendapatkan output yang berarti) . Saya pernah mendengar TAU memiliki kemampuan yang serupa.
Ini adalah dua metode yang saya gunakan untuk mempercepat kode saya:
Untuk aplikasi yang terikat CPU:
Gunakan profiler dalam mode DEBUG untuk mengidentifikasi bagian yang dipertanyakan dari kode Anda
Kemudian beralih ke mode RELEASE dan komentar bagian yang dipertanyakan dari kode Anda (berhenti tanpa apa-apa) sampai Anda melihat perubahan dalam kinerja.
Untuk aplikasi terikat I / O:
Gunakan profiler dalam mode RELEASE untuk mengidentifikasi bagian kode Anda yang dipertanyakan.
NB
Jika Anda tidak memiliki profiler, gunakan profiler orang miskin itu. Hit jeda saat debug aplikasi Anda. Sebagian besar suite pengembang akan bergabung dengan nomor baris yang dikomentari. Secara statistik Anda cenderung mendarat di wilayah yang mengonsumsi sebagian besar siklus CPU Anda.
Untuk CPU, alasan untuk membuat profil dalam mode DEBUG adalah karena jika Anda mencoba membuat profil dalam mode RELEASE , kompiler akan mengurangi matematika, loop vektorisasi, dan fungsi sebaris yang cenderung menggumpal kode Anda menjadi kekacauan yang tidak dapat dipetakan ketika dirakit. Kekacauan yang tidak dapat dipetakan berarti profiler Anda tidak akan dapat dengan jelas mengidentifikasi apa yang perlu waktu lama karena perakitan mungkin tidak sesuai dengan kode sumber yang sedang dioptimalkan . Jika Anda memerlukan kinerja (misalnya sensitif terhadap waktu) dari mode RELEASE , nonaktifkan fitur debugger yang diperlukan untuk menjaga kinerja yang dapat digunakan.
Untuk I / O-terikat, profiler masih dapat mengidentifikasi operasi I / O dalam mode RELEASE karena operasi I / O terkait secara eksternal dengan perpustakaan bersama (sebagian besar waktu) atau dalam kasus terburuk, akan menghasilkan sistem panggil vektor interupsi (yang juga mudah diidentifikasi oleh profiler).
+1 Metode orang miskin bekerja dengan baik untuk I / O terikat serta untuk CPU terikat, dan saya sarankan melakukan semua penyetelan kinerja dalam mode DEBUG. Setelah selesai menyetel, lalu nyalakan RELEASE. Ini akan membuat peningkatan jika program terikat dengan CPU dalam kode Anda. Berikut video singkat tapi kasar dari proses tersebut.
Mike Dunlavey
3
Saya tidak akan menggunakan build DEBUG untuk profil kinerja. Seringkali saya melihat bahwa bagian-bagian penting kinerja dalam mode DEBUG sepenuhnya dioptimalkan dalam mode rilis. Masalah lain adalah penggunaan menegaskan dalam kode debug yang menambah kebisingan pada kinerja.
gast128
3
Apakah Anda membaca posting saya sama sekali? "Jika Anda memerlukan kinerja (misalnya sensitif terhadap waktu) dari mode RELEASE, nonaktifkan fitur debugger yang diperlukan untuk menjaga kinerja yang dapat digunakan", "Kemudian beralih ke mode RELEASE dan komentar bagian yang dipertanyakan dari kode Anda (Stub tanpa apa-apa) sampai Anda melihat perubahan kinerja. "? Saya mengatakan memeriksa kemungkinan area masalah dalam mode debug dan memverifikasi masalah-masalah itu dalam mode rilis untuk menghindari jebakan yang Anda sebutkan.
Ini lintas platform dan memungkinkan Anda untuk tidak mengukur kinerja aplikasi Anda juga secara real-time. Anda bahkan dapat memasangkannya dengan grafik langsung. Penafian penuh: Saya adalah penulis.
Anda dapat menggunakan kerangka kerja pencatatan seperti logurukarena ia menyertakan cap waktu dan total waktu kerja yang dapat digunakan dengan baik untuk membuat profil:
Di tempat kerja kami memiliki alat yang sangat bagus yang membantu kami memantau apa yang kami inginkan dalam hal penjadwalan. Ini telah berguna beberapa kali.
Ini dalam C ++ dan harus disesuaikan dengan kebutuhan Anda. Sayangnya saya tidak bisa membagikan kode, hanya konsep. Anda menggunakan volatilebuffer "besar" yang berisi cap waktu dan ID aktivitas yang dapat Anda buang post mortem atau setelah menghentikan sistem logging (dan misalnya, membuangnya ke file).
Anda mengambil buffer yang disebut besar dengan semua data dan antarmuka kecil mem-parsingnya dan menampilkan peristiwa dengan nama (nilai naik / turun) seperti osiloskop dengan warna (dikonfigurasi dalam .hppfile).
Anda menyesuaikan jumlah acara yang dihasilkan untuk fokus hanya pada apa yang Anda inginkan. Ini banyak membantu kami untuk masalah penjadwalan sambil mengonsumsi jumlah CPU yang kami inginkan berdasarkan jumlah peristiwa yang dicatat per detik.
Anda membutuhkan 3 file:
toolname.hpp // interface
toolname.cpp // code
tool_events_id.hpp // Events ID
Konsepnya adalah untuk mendefinisikan peristiwa tool_events_id.hppseperti itu:
Di mana pun dalam kode Anda, Anda dapat menggunakan:
toolname<LOG_LEVEL>::log(EVENT_NAME,VALUE);
The probefungsi menggunakan beberapa lini perakitan untuk mengambil jam timestamp ASAP dan kemudian menetapkan entri dalam buffer. Kami juga memiliki peningkatan atom untuk menemukan indeks tempat penyimpanan log dengan aman. Tentu saja buffer berbentuk lingkaran.
Semoga idenya tidak dikaburkan oleh kurangnya kode sampel.
Sebenarnya sedikit terkejut tidak banyak disebutkan tentang google / benchmark , sementara itu agak rumit untuk menyematkan area kode tertentu, khususnya jika basis kode sedikit besar, namun saya menemukan ini sangat membantu ketika digunakan dalam kombinasi dengancallgrind
IMHO mengidentifikasi bagian yang menyebabkan kemacetan adalah kuncinya di sini. Namun saya akan mencoba dan menjawab pertanyaan-pertanyaan berikut terlebih dahulu dan memilih alat berdasarkan itu
apakah algoritme saya benar?
apakah ada kunci yang terbukti sebagai leher botol?
apakah ada bagian kode tertentu yang terbukti menjadi pelakunya?
bagaimana dengan IO, ditangani dan dioptimalkan?
valgrinddengan kombinasi callrinddan kcachegrindharus memberikan estimasi yang layak pada poin-poin di atas dan setelah itu ditetapkan bahwa ada masalah dengan beberapa bagian kode, saya sarankan melakukan micro bench mark google benchmarkadalah tempat yang baik untuk memulai.
Gunakan -pgbendera saat mengkompilasi dan menautkan kode dan menjalankan file yang dapat dieksekusi. Saat program ini dijalankan, profiling data dikumpulkan dalam file a.out.
Ada dua jenis profil yang berbeda
1- Profil datar:
dengan menjalankan perintah, gprog --flat-profile a.outAnda mendapatkan data berikut
- berapa persen dari keseluruhan waktu yang dihabiskan untuk fungsi,
- berapa detik yang dihabiskan dalam suatu fungsi — termasuk dan tidak termasuk panggilan ke subfungsi,
- jumlah panggilan,
- waktu rata-rata per panggilan.
2 - grafik profiling
kita perintah gprof --graph a.outuntuk mendapatkan data berikut untuk setiap fungsi yang meliputi
- Di setiap bagian, satu fungsi ditandai dengan nomor indeks.
- Di atas fungsi, ada daftar fungsi yang memanggil fungsi.
- Fungsi di bawah ini, ada daftar fungsi yang dipanggil oleh fungsi.
Karena tidak ada yang menyebutkan Arm MAP, saya akan menambahkan secara pribadi saya telah berhasil menggunakan Peta ke profil program ilmiah C ++.
Arm MAP adalah profiler untuk kode C, C ++, Fortran, dan F90 yang paralel, multithreaded, atau tunggal. Ini memberikan analisis mendalam dan menentukan titik kemacetan ke baris sumber. Tidak seperti kebanyakan profiler, ini dirancang untuk dapat profil pthreads, OpenMP atau MPI untuk kode paralel dan berulir.
menggunakan perangkat lunak debug
bagaimana mengidentifikasi di mana kode berjalan lambat?
hanya berpikir Anda memiliki hambatan saat Anda bergerak maka itu akan menurunkan kecepatan Anda
seperti itu pengulangan realokasi yang tidak diinginkan, buffer overflows, pencarian, kebocoran memori dll operasi mengkonsumsi lebih banyak daya eksekusi itu akan berpengaruh buruk terhadap kinerja kode, Pastikan untuk menambahkan -pg ke kompilasi sebelum membuat profil:
g++ your_prg.cpp -pgatau cc my_program.cpp -g -pgsesuai kompiler Anda
belum mencobanya tetapi saya pernah mendengar hal-hal baik tentang google-perftools. Ini pasti patut dicoba.
valgrind --tool=callgrind ./(Your binary)
Ini akan menghasilkan file bernama gmon.out atau callgrind.out.x. Anda kemudian dapat menggunakan alat kcachegrind atau debugger untuk membaca file ini. Ini akan memberi Anda analisis grafis dari hal-hal dengan hasil seperti garis mana yang menghabiskan biaya.
code
profiler. Namun, inversi prioritas, alias cache, pertentangan sumber daya, dll. Semuanya dapat menjadi faktor dalam mengoptimalkan dan kinerja. Saya pikir orang membaca informasi ke dalam kode lambat saya . FAQ sedang mereferensikan utas ini.Jawaban:
Jika tujuan Anda adalah menggunakan profiler, gunakan salah satu yang disarankan.
Namun, jika Anda sedang terburu-buru dan Anda dapat secara manual menginterupsi program Anda di bawah debugger ketika sedang lambat, ada cara sederhana untuk menemukan masalah kinerja.
Hentikan beberapa kali, dan setiap kali lihat tumpukan panggilan. Jika ada beberapa kode yang membuang-buang persentase waktu, 20% atau 50% atau apa pun, itu adalah probabilitas bahwa Anda akan menangkapnya dalam tindakan pada setiap sampel. Jadi, kira-kira persentase sampel yang Anda akan melihatnya. Tidak ada dugaan yang berpendidikan. Jika Anda memiliki dugaan tentang apa masalahnya, ini akan membuktikan atau membantahnya.
Anda mungkin memiliki beberapa masalah kinerja berbagai ukuran. Jika Anda membersihkan salah satu dari mereka, yang tersisa akan mengambil persentase lebih besar, dan lebih mudah dikenali, pada lintasan selanjutnya. Efek pembesaran ini , ketika diperparah dengan berbagai masalah, dapat menyebabkan faktor percepatan yang sangat besar.
Peringatan : Pemrogram cenderung skeptis terhadap teknik ini kecuali mereka telah menggunakannya sendiri. Mereka akan mengatakan bahwa profiler memberi Anda informasi ini, tetapi itu hanya benar jika mereka mencicipi seluruh tumpukan panggilan, dan kemudian membiarkan Anda memeriksa satu set sampel acak. (Ringkasan adalah tempat wawasan hilang.) Grafik panggilan tidak memberi Anda informasi yang sama, karena
Mereka juga akan mengatakan itu hanya bekerja pada program mainan, ketika sebenarnya itu bekerja pada program apa pun, dan tampaknya bekerja lebih baik pada program yang lebih besar, karena mereka cenderung memiliki lebih banyak masalah untuk ditemukan. Mereka akan mengatakan itu kadang-kadang menemukan hal-hal yang tidak masalah, tetapi itu hanya benar jika Anda melihat sesuatu sekali . Jika Anda melihat masalah pada lebih dari satu sampel, itu nyata.
PS Ini juga dapat dilakukan pada program multi-utas jika ada cara untuk mengumpulkan sampel panggilan-tumpukan dari kumpulan utas pada suatu titik waktu, seperti yang ada di Jawa.
PPS Sebagai generalitas kasar, semakin banyak lapisan abstraksi yang Anda miliki dalam perangkat lunak Anda, semakin besar kemungkinan Anda akan menemukan bahwa itu adalah penyebab masalah kinerja (dan peluang untuk mendapatkan peningkatan kecepatan).
Ditambahkan : Ini mungkin tidak jelas, tetapi teknik stack sampling bekerja sama baiknya di hadapan rekursi. Alasannya adalah bahwa waktu yang akan disimpan dengan menghapus instruksi diperkirakan oleh fraksi sampel yang mengandungnya, terlepas dari berapa kali itu dapat terjadi dalam sampel.
Keberatan lain yang sering saya dengar adalah: " Ini akan berhenti di suatu tempat secara acak, dan itu akan kehilangan masalah sebenarnya ". Ini berasal dari memiliki konsep sebelumnya tentang apa masalah sebenarnya. Properti utama dari masalah kinerja adalah bahwa mereka menentang harapan. Sampling memberi tahu Anda bahwa ada masalah, dan reaksi pertama Anda adalah tidak percaya. Itu wajar, tetapi Anda bisa yakin jika menemukan masalah itu nyata, dan sebaliknya.
Ditambahkan : Biarkan saya membuat penjelasan Bayesian tentang cara kerjanya. Misalkan ada beberapa instruksi
I
(panggilan atau lainnya) yang ada di panggilan menumpuk sebagianf
waktu (dan dengan demikian biaya yang banyak). Untuk kesederhanaan, anggaplah kita tidak tahu apaf
itu, tetapi anggaplah itu adalah 0,1, 0,2, 0,3, ... 0,9, 1,0, dan probabilitas sebelumnya dari masing-masing kemungkinan ini adalah 0,1, sehingga semua biaya ini kemungkinan sama besarnya a-priori.Kemudian anggaplah kita mengambil hanya 2 tumpukan sampel, dan kita melihat instruksi
I
pada kedua sampel, pengamatan yang ditunjuko=2/2
. Ini memberi kita perkiraan baru dari frekuensif
dariI
, menurut ini:Kolom terakhir mengatakan bahwa, misalnya, probabilitas bahwa
f
> = 0,5 adalah 92%, naik dari asumsi sebelumnya sebesar 60%.Misalkan asumsi sebelumnya berbeda. Misalkan kita anggap
P(f=0.1)
0,991 (hampir pasti), dan semua kemungkinan lain hampir tidak mungkin (0,001). Dengan kata lain, kepastian kami sebelumnya adalah yangI
murah. Lalu kita dapatkan:Sekarang dikatakan
P(f >= 0.5)
26%, naik dari asumsi sebelumnya 0,6%. Jadi Bayes memungkinkan kami memperbarui perkiraan biaya yang mungkin terjadiI
. Jika jumlah data kecil, itu tidak memberi tahu kami secara akurat berapa biayanya, hanya bahwa itu cukup besar untuk diperbaiki.Namun cara lain untuk melihatnya disebut Aturan Suksesi . Jika Anda melempar koin 2 kali, dan muncul dua kali di kepala, apa artinya itu memberi tahu Anda tentang kemungkinan bobot koin? Cara yang dihormati untuk menjawab adalah dengan mengatakan bahwa itu adalah distribusi Beta, dengan nilai rata-rata
(number of hits + 1) / (number of tries + 2) = (2+1)/(2+2) = 75%
.(Kuncinya adalah bahwa kita melihat
I
lebih dari sekali. Jika kita hanya melihatnya sekali, itu tidak memberi tahu kita banyak kecuali bahwaf
> 0.)Jadi, bahkan sejumlah kecil sampel dapat memberi tahu kami banyak tentang biaya instruksi yang dilihatnya. (Dan itu akan melihat mereka dengan frekuensi, rata-rata, sebanding dengan biaya mereka. Jika
n
sampel yang diambil, danf
biaya, makaI
akan muncul dinf+/-sqrt(nf(1-f))
sampel. Contoh,n=10
,f=0.3
, yang3+/-1.4
sampel.)Ditambahkan : Untuk memberikan nuansa intuitif untuk perbedaan antara pengukuran dan pengambilan sampel tumpukan acak:
Ada profiler sekarang yang mengambil sampel tumpukan, bahkan pada waktu jam dinding, tetapi yang keluar adalah pengukuran (atau jalur panas, atau hot spot, dari mana "bottleneck" dapat dengan mudah disembunyikan). Apa yang mereka tidak perlihatkan kepada Anda (dan mereka dengan mudah bisa) adalah sampel yang sebenarnya. Dan jika tujuan Anda adalah menemukan kemacetan, jumlah yang perlu Anda lihat adalah, rata-rata , 2 dibagi dengan sebagian kecil dari waktu yang dibutuhkan. Jadi jika dibutuhkan 30% waktu, 2 / 0,3 = 6,7 sampel, rata-rata, akan menunjukkannya, dan kemungkinan 20 sampel akan menunjukkan itu adalah 99,2%.
Berikut ini adalah ilustrasi off-the-cuff perbedaan antara memeriksa pengukuran dan memeriksa sampel tumpukan. Kemacetan bisa jadi satu gumpalan besar seperti ini, atau banyak gumpalan kecil, tidak ada bedanya.
Pengukuran horisontal; ia memberi tahu Anda berapa lama waktu yang dibutuhkan untuk rutinitas khusus. Pengambilan sampel adalah vertikal. Jika ada cara untuk menghindari apa yang dilakukan seluruh program pada saat itu, dan jika Anda melihatnya pada sampel kedua , Anda telah menemukan hambatannya. Itulah yang membuat perbedaan - melihat seluruh alasan waktu yang dihabiskan, bukan hanya berapa banyak.
sumber
Anda dapat menggunakan Valgrind dengan opsi berikut
Ini akan menghasilkan file bernama
callgrind.out.x
. Anda kemudian dapat menggunakankcachegrind
alat untuk membaca file ini. Ini akan memberi Anda analisis grafis dari hal-hal dengan hasil seperti garis mana yang menghabiskan biaya.sumber
./gprof2dot.py -f callgrind callgrind.out.x | dot -Tsvg -o output.svg
gprof2dot
ada di sini sekarang: github.com/jrfonseca/gprof2dotSaya menganggap Anda menggunakan GCC. Solusi standar adalah profil dengan gprof .
Pastikan untuk menambah
-pg
kompilasi sebelum membuat profil:Saya belum mencobanya tetapi saya pernah mendengar hal-hal baik tentang google-perftools . Ini pasti patut dicoba.
Pertanyaan terkait di sini .
Beberapa kata kunci lain jika
gprof
tidak melakukan pekerjaan untuk Anda: Valgrind , Intel VTune , Sun DTrace .sumber
Kernel yang lebih baru (mis. Kernel Ubuntu terbaru) hadir dengan alat 'perf' baru (
apt-get install linux-tools
) AKA perf_events .Ini datang dengan profiler pengambilan sampel klasik ( halaman manual ) serta timechart yang mengagumkan !
Yang penting adalah bahwa alat-alat ini dapat berupa sistem profiling dan bukan hanya proses profiling - mereka dapat menunjukkan interaksi antara utas, proses dan kernel dan membiarkan Anda memahami penjadwalan dan dependensi I / O antara proses.
sumber
perf report
sepertinya memberi saya nama fungsi dengan orang tua panggilan ... (jadi ini semacam tampilan kupu-kupu terbalik)gprof2dot
danperf script
. Alat yang sangat bagus!perf
ada di archive.li/9r927#selection-767.126-767.271 (Mengapa para dewa SO memutuskan untuk menghapus halaman itu dari basis pengetahuan SO adalah di luar saya ....)Saya akan menggunakan Valgrind dan Callgrind sebagai dasar untuk rangkaian alat profiling saya. Yang penting diketahui adalah bahwa Valgrind pada dasarnya adalah Mesin Virtual:
Callgrind adalah profiler yang dibangun di atas itu. Manfaat utama adalah Anda tidak perlu menjalankan aplikasi selama berjam-jam untuk mendapatkan hasil yang andal. Bahkan satu run kedua sudah cukup untuk mendapatkan hasil yang solid, andal, karena Callgrind adalah profiler non-probing .
Alat lain yang dibangun di atas Valgrind adalah Massif. Saya menggunakannya untuk penggunaan memori tumpukan profil. Ini bekerja dengan baik. Apa yang dilakukannya adalah memberi Anda snapshot dari penggunaan memori - informasi terperinci APA yang memegang persentase memori APA, dan WHO telah meletakkannya di sana. Informasi tersebut tersedia di berbagai titik waktu aplikasi dijalankan.
sumber
Jawaban untuk menjalankan
valgrind --tool=callgrind
tidak cukup lengkap tanpa beberapa opsi. Kami biasanya tidak ingin profil 10 menit waktu startup lambat di bawah Valgrind dan ingin profil program kami ketika sedang melakukan beberapa tugas.Jadi ini yang saya rekomendasikan. Jalankan program terlebih dahulu:
Sekarang ketika ia berfungsi dan kami ingin memulai pembuatan profil, kami harus menjalankannya di jendela lain:
Ini mengaktifkan profil. Untuk mematikannya dan menghentikan seluruh tugas yang mungkin kita gunakan:
Sekarang kami memiliki beberapa file bernama callgrind.out. * Di direktori saat ini. Untuk melihat hasil pembuatan profil, gunakan:
Saya sarankan di jendela berikutnya untuk mengklik tajuk kolom "Cukup", jika tidak, ini menunjukkan bahwa "main ()" adalah tugas yang paling memakan waktu. "Diri" menunjukkan seberapa banyak masing-masing fungsi itu sendiri memakan waktu, tidak bersama-sama dengan tanggungan.
sumber
CALLGRIND_TOGGLE_COLLECT
untuk mengaktifkan / menonaktifkan koleksi secara terprogram; lihat stackoverflow.com/a/13700817/288875Ini adalah jawaban atas jawaban Gprof Nazgob .
Saya telah menggunakan Gprof beberapa hari terakhir dan telah menemukan tiga batasan signifikan, salah satunya saya belum melihat didokumentasikan di tempat lain (belum):
Itu tidak bekerja dengan baik pada kode multi-threaded, kecuali jika Anda menggunakan solusi
Grafik panggilan menjadi bingung oleh pointer fungsi. Contoh: Saya memiliki fungsi yang dipanggil
multithread()
yang memungkinkan saya untuk melakukan multi-utas fungsi yang ditentukan pada array yang ditentukan (keduanya dilewatkan sebagai argumen). Namun, lihat semua panggilanmultithread()
sebagai setara untuk keperluan menghitung waktu yang dihabiskan pada anak-anak. Karena beberapa fungsi yang sayamultithread()
anggap lebih lama dari yang lain, grafik panggilan saya sebagian besar tidak berguna. (Bagi mereka yang bertanya-tanya apakah threading adalah masalah di sini: tidak,multithread()
bisa opsional, dan memang dalam hal ini, jalankan semuanya secara berurutan pada utas panggilan saja).Dikatakan di sini bahwa "... jumlah angka panggilan diperoleh dengan menghitung, bukan pengambilan sampel. Angka tersebut sepenuhnya akurat ...". Namun saya menemukan grafik panggilan saya memberi saya 5345859132 + 784984078 sebagai statistik panggilan untuk fungsi saya yang paling dipanggil, di mana nomor pertama seharusnya menjadi panggilan langsung, dan panggilan rekursif kedua (yang semuanya dari dirinya sendiri). Karena ini tersirat saya punya bug, saya memasukkan penghitung panjang (64-bit) ke dalam kode dan melakukan hal yang sama lagi. Hitungan saya: 5345859132 langsung, dan 78094395406 panggilan rekursif diri. Ada banyak digit di sana, jadi saya akan menunjukkan panggilan rekursif yang saya ukur adalah 78bn, dibandingkan 784m dari Gprof: faktor 100 berbeda. Keduanya berjalan adalah kode berulir tunggal dan tidak dioptimalkan, satu dikompilasi
-g
dan yang lainnya-pg
.Ini adalah GNU Gprof (GNU Binutils for Debian) 2.18.0.20080103 berjalan di bawah Debian Lenny 64-bit, jika itu membantu siapa pun.
sumber
Gunakan Valgrind, callgrind, dan kcachegrind:
menghasilkan callgrind.out.x. Baca ini menggunakan kcachegrind.
Gunakan gprof (tambahkan -pg):
(tidak begitu baik untuk multi-utas, pointer fungsi)
Gunakan google-perftools:
Menggunakan sampling waktu, I / O dan kemacetan CPU terungkap.
Intel VTune adalah yang terbaik (gratis untuk tujuan pendidikan).
Lainnya: AMD Codeanalyst (sejak diganti dengan AMD CodeXL), OProfile, alat 'perf' (apt-get install linux-tools)
sumber
Survei teknik profiling C ++
Dalam jawaban ini, saya akan menggunakan beberapa alat berbeda untuk menganalisis beberapa program pengujian yang sangat sederhana, untuk membandingkan secara konkret cara kerja alat tersebut.
Program pengujian berikut ini sangat sederhana dan melakukan hal berikut:
main
panggilanfast
danmaybe_slow
3 kali, salah satumaybe_slow
panggilan menjadi lambatPanggilan lambat
maybe_slow
adalah 10x lebih lama, dan mendominasi runtime jika kami mempertimbangkan panggilan ke fungsi anakcommon
. Idealnya, alat profiling akan dapat mengarahkan kita ke panggilan lambat tertentu.keduanya
fast
danmaybe_slow
panggilancommon
, yang menyumbang sebagian besar pelaksanaan programAntarmuka program adalah:
dan program ini melakukan
O(n^2)
loop secara total.seed
hanya untuk mendapatkan output yang berbeda tanpa mempengaruhi runtime.main.c
gprof
gprof membutuhkan kompilasi ulang perangkat lunak dengan instrumentasi, dan itu juga menggunakan pendekatan pengambilan sampel bersama dengan instrumentasi itu. Karena itu, ia menemukan keseimbangan antara akurasi (pengambilan sampel tidak selalu sepenuhnya akurat dan dapat melewati fungsi) dan pelambatan eksekusi (instrumentasi dan pengambilan sampel adalah teknik yang relatif cepat yang tidak terlalu memperlambat eksekusi).
gprof terintegrasi dengan GCC / binutils, jadi yang harus kita lakukan adalah mengkompilasi dengan
-pg
opsi untuk mengaktifkan gprof. Kami kemudian menjalankan program secara normal dengan parameter CLI ukuran yang menghasilkan jangka waktu yang wajar beberapa detik (10000
):Untuk alasan pendidikan, kami juga akan menjalankan tanpa mengaktifkan optimisasi. Perhatikan bahwa ini tidak berguna dalam praktik, karena Anda biasanya hanya peduli untuk mengoptimalkan kinerja program yang dioptimalkan:
Pertama,
time
beri tahu kami bahwa waktu eksekusi dengan dan tanpa-pg
sama, yang hebat: tidak ada perlambatan! Namun saya telah melihat akun perlambatan 2x - 3x pada perangkat lunak yang kompleks, misalnya seperti yang ditunjukkan dalam tiket ini .Karena kami kompilasi dengan
-pg
, menjalankan program menghasilkan filegmon.out
file yang berisi data profil.Kita dapat mengamati file itu secara grafis dengan
gprof2dot
seperti yang ditanyakan di: Apakah mungkin untuk mendapatkan representasi grafis dari hasil gprof?Di sini,
gprof
alat membacagmon.out
informasi jejak, dan menghasilkan laporan yang dapat dibaca manusiamain.gprof
, yanggprof2dot
kemudian dibaca untuk menghasilkan grafik.Sumber untuk gprof2dot ada di: https://github.com/jrfonseca/gprof2dot
Kami mengamati hal-hal berikut untuk
-O0
pelarian:dan untuk
-O3
pelarian:The
-O0
output cukup banyak jelas. Sebagai contoh, ini menunjukkan bahwa 3maybe_slow
panggilan dan panggilan anak mereka mengambil 97,56% dari total runtime, meskipun eksekusimaybe_slow
itu sendiri tanpa anak-anak menyumbang 0,00% dari total waktu eksekusi, yaitu hampir semua waktu yang dihabiskan dalam fungsi tersebut dihabiskan untuk panggilan anak.TODO: mengapa
main
hilang dari-O3
output, meskipun saya bisa melihatnya dibt
dalam GDB? Fungsi yang hilang dari keluaran GProf saya pikir itu karena gprof juga berdasarkan sampel selain instrumentasi yang dikompilasi, dan-O3
main
terlalu cepat dan tidak punya sampel.Saya memilih output SVG daripada PNG karena SVG dapat dicari dengan Ctrl + F dan ukuran file bisa sekitar 10x lebih kecil. Selain itu, lebar dan tinggi gambar yang dihasilkan dapat menjadi sangat muda dengan puluhan ribu piksel untuk perangkat lunak yang kompleks, dan
eog
bug GNOME 3.28.1 keluar dalam hal itu untuk PNG, sementara SVG dibuka oleh browser saya secara otomatis. gimp 2.8 bekerja dengan baik, lihat juga:tetapi meskipun demikian, Anda akan banyak menyeret gambar di sekitar untuk menemukan apa yang Anda inginkan, lihat misalnya gambar ini dari contoh perangkat lunak "nyata" yang diambil dari tiket ini :
Dapatkah Anda menemukan tumpukan panggilan yang paling penting dengan mudah dengan semua garis spaghetti kecil yang tidak disortir saling bertabrakan? Mungkin ada
dot
opsi yang lebih baik saya yakin, tetapi saya tidak ingin pergi ke sana sekarang. Yang benar-benar kita butuhkan adalah pemirsa khusus yang berdedikasi untuk itu, tetapi saya belum menemukannya:Namun Anda dapat menggunakan peta warna untuk sedikit mengurangi masalah tersebut. Misalnya, pada gambar besar sebelumnya, saya akhirnya berhasil menemukan jalur kritis di sebelah kiri ketika saya membuat deduksi cemerlang bahwa hijau muncul setelah merah, diikuti akhirnya dengan biru yang lebih gelap dan lebih gelap.
Atau, kita juga dapat mengamati keluaran teks dari
gprof
alat binutils bawaan yang sebelumnya kita simpan di:Secara default, ini menghasilkan output yang sangat verbose yang menjelaskan apa artinya data output. Karena saya tidak bisa menjelaskan lebih baik dari itu, saya akan membiarkan Anda membacanya sendiri.
Setelah Anda memahami format output data, Anda dapat mengurangi verbositas untuk hanya menampilkan data tanpa tutorial dengan
-b
opsi:Dalam contoh kami, output untuk
-O0
:dan untuk
-O3
:Sebagai ringkasan yang sangat cepat untuk setiap bagian, misalnya:
berpusat di sekitar fungsi yang dibiarkan berlekuk (
maybe_flow
).[3]
adalah ID dari fungsi itu. Di atas fungsi, ada peneleponnya, dan di bawahnya ada callees.Untuk
-O3
, lihat di sini seperti pada keluaran grafis itumaybe_slow
danfast
tidak memiliki orangtua yang dikenal, yang merupakan arti dari dokumentasi itu<spontaneous>
.Saya tidak yakin apakah ada cara yang baik untuk melakukan profil garis-demi-baris dengan gprof: `gprof` waktu yang dihabiskan dalam baris kode tertentu
valgrind callgrind
valgrind menjalankan program melalui mesin virtual valgrind. Ini membuat profil sangat akurat, tetapi juga menghasilkan perlambatan program yang sangat besar. Saya juga telah menyebutkan kcachegrind sebelumnya di: Alat untuk mendapatkan grafik panggilan fungsi bergambar kode
callgrind adalah alat valgrind untuk kode profil dan kcachegrind adalah program KDE yang dapat memvisualisasikan output cachegrind.
Pertama kita harus menghapus
-pg
flag untuk kembali ke kompilasi normal, jika tidak run sebenarnya gagalProfiling timer expired
, dan ya, ini sangat umum yang saya lakukan dan ada pertanyaan Stack Overflow untuk itu.Jadi kami mengkompilasi dan menjalankan sebagai:
Saya mengaktifkan
--dump-instr=yes --collect-jumps=yes
karena ini juga membuang informasi yang memungkinkan kami melihat gangguan kinerja per jalur perakitan, dengan biaya overhead tambahan yang relatif kecil.Off the bat,
time
memberitahu kami bahwa program ini membutuhkan waktu 29,5 detik untuk dieksekusi, jadi kami mengalami penurunan sekitar 15x pada contoh ini. Jelas, perlambatan ini akan menjadi batasan serius untuk beban kerja yang lebih besar. Pada "contoh perangkat lunak dunia nyata" yang disebutkan di sini , saya mengamati penurunan 80x.Proses menghasilkan file data profil bernama
callgrind.out.<pid>
egcallgrind.out.8554
dalam kasus saya. Kami melihat file itu dengan:yang menunjukkan GUI yang berisi data yang mirip dengan output gprof tekstual:
Juga, jika kita pergi ke kanan bawah "Grafik Panggilan" tab, kita melihat grafik panggilan yang dapat kita ekspor dengan mengklik kanan untuk mendapatkan gambar berikut dengan jumlah batas putih yang tidak masuk akal :-)
Saya pikir
fast
tidak muncul pada grafik itu karena kcachegrind pasti telah menyederhanakan visualisasi karena panggilan itu memakan waktu terlalu sedikit, ini kemungkinan akan menjadi perilaku yang Anda inginkan pada program nyata. Menu klik kanan memiliki beberapa pengaturan untuk mengontrol kapan harus menyisihkan node seperti itu, tetapi saya tidak bisa membuatnya untuk menampilkan panggilan singkat setelah upaya cepat. Jika saya mengklik padafast
jendela kiri, itu memang menampilkan grafik panggilanfast
, sehingga tumpukan itu benar-benar ditangkap. Belum ada yang menemukan cara untuk menampilkan grafik panggilan grafik lengkap: Buat panggilan panggil tunjukkan semua panggilan fungsi di kcachegrind callgraphTODO pada perangkat lunak C ++ yang kompleks, saya melihat beberapa entri tipe
<cycle N>
, misalnya di<cycle 11>
mana saya mengharapkan nama fungsi, apa artinya itu? Saya perhatikan ada tombol "Deteksi Siklus" untuk menghidupkan dan mematikannya, tetapi apa artinya?perf
darilinux-tools
perf
tampaknya menggunakan mekanisme pengambilan sampel kernel Linux secara eksklusif. Ini membuatnya sangat mudah untuk diatur, tetapi juga tidak sepenuhnya akurat.Ini menambahkan 0,2s ke eksekusi, jadi kami baik-baik saja waktu, tapi saya masih tidak melihat banyak minat, setelah memperluas
common
node dengan panah kanan keyboard:Jadi saya mencoba membuat tolok ukur
-O0
program untuk melihat apakah itu menunjukkan sesuatu, dan hanya sekarang, akhirnya, saya melihat grafik panggilan:TODO: apa yang terjadi pada
-O3
eksekusi? Apakah hanya itumaybe_slow
danfast
terlalu cepat dan tidak mendapatkan sampel? Apakah ini bekerja dengan baik-O3
pada program yang lebih besar yang membutuhkan waktu lebih lama untuk dijalankan? Apakah saya melewatkan beberapa opsi CLI? Saya menemukan tentang-F
untuk mengontrol frekuensi sampel dalam Hertz, tetapi saya mengubahnya hingga maks diizinkan secara default-F 39500
(dapat ditingkatkan dengansudo
) dan saya masih tidak melihat panggilan yang jelas.Satu hal keren tentang
perf
alat FlameGraph dari Brendan Gregg yang menampilkan pengaturan waktu panggilan dengan cara yang sangat rapi yang memungkinkan Anda untuk dengan cepat melihat panggilan besar. Alat ini tersedia di: https://github.com/brendangregg/FlameGraph dan juga disebutkan pada nya Perf tutorial di: http://www.brendangregg.com/perf.html#FlameGraphs Ketika aku berlariperf
tanpasudo
akuERROR: No stack counts found
jadi untuk sekarang saya akan melakukannya dengansudo
:tetapi dalam program sederhana seperti itu, keluarannya tidak mudah dipahami, karena kita tidak dapat dengan mudah melihat
maybe_slow
maupunfast
pada grafik itu:Pada contoh yang lebih kompleks, menjadi jelas apa arti grafik:
TODO ada log
[unknown]
fungsi dalam contoh itu, mengapa begitu?Antarmuka GUI perf lain yang mungkin layak termasuk:
Plugin Eclipse Trace Compass: https://www.eclipse.org/tracecompass/
Tetapi ini memiliki kelemahan yaitu Anda harus terlebih dahulu mengonversi data ke Format Jejak Umum, yang dapat dilakukan dengan
perf data --to-ctf
, tetapi harus diaktifkan pada waktu membangun / memilikiperf
cukup baru, yang keduanya tidak berlaku untuk perf di Ubuntu 18.04https://github.com/KDAB/hotspot
Kelemahan dari ini adalah bahwa sepertinya tidak ada paket Ubuntu, dan membangunnya membutuhkan Qt 5.10 sedangkan Ubuntu 18.04 adalah pada Qt 5.9.
gperftools
Sebelumnya disebut "Google Performance Tools", sumber: https://github.com/gperftools/gperftools Berbasis sampel.
Pertama instal gperftools dengan:
Kemudian, kita dapat mengaktifkan profiler CPU gperftools dalam dua cara: saat runtime, atau saat membangun.
Pada saat runtime, kita harus melewati set
LD_PRELOAD
to point kelibprofiler.so
, yang dapat Anda temukanlocate libprofiler.so
, misalnya di sistem saya:Atau, kita dapat membangun pustaka pada saat tautan, membagikan lewat
LD_PRELOAD
saat runtime:Lihat juga: gperftools - file profil tidak dibuang
Cara terbaik untuk melihat data ini yang saya temukan sejauh ini adalah membuat pprof output dalam format yang sama dengan yang diambil oleh kcachegrind sebagai input (ya, alat Valgrind-project-viewer-tool) dan gunakan kcachegrind untuk melihat bahwa:
Setelah berjalan dengan salah satu metode tersebut, kami mendapatkan
prof.out
file data profil sebagai output. Kita dapat melihat file itu secara grafis sebagai SVG dengan:yang memberi sebagai grafik panggilan akrab seperti alat lain, tetapi dengan unit kikuk jumlah sampel daripada detik.
Atau, kita juga bisa mendapatkan beberapa data tekstual dengan:
pemberian yang mana:
Lihat juga: Cara menggunakan alat google perf
Diuji di Ubuntu 18.04, gprof2dot 2019.11.30, valgrind 3.13.0, perf 4.15.18, kernel Linux 4.15.0, FLameGraph 1a0dc6985aad06e76857cf2a354bd5ba0c9ce96b, gperftools 2.5-2.
sumber
-fno-omit-frame-pointer
flag atau menggunakan alternatif lain: merekam dengan--call-graph "dwarf"
atau--call-graph "lbr"
tergantung pada skenario Anda.Untuk program berulir tunggal, Anda dapat menggunakan igprof , The Ignominous Profiler: https://igprof.org/ .
Ini adalah profiler pengambilan sampel, di sepanjang baris ... panjang ... jawaban oleh Mike Dunlavey, yang akan membungkus hasil dalam susunan pohon panggilan yang dapat dijelajahi, dijelaskan dengan waktu atau memori yang dihabiskan di setiap fungsi, baik kumulatif atau per-fungsi.
sumber
Juga layak disebutkan
Saya telah menggunakan HPCToolkit dan VTune dan mereka sangat efektif dalam menemukan kutub panjang di tenda dan tidak perlu kode Anda untuk dikompilasi ulang (kecuali bahwa Anda harus menggunakan tipe -g -O atau RelWithDebInfo di CMake untuk mendapatkan output yang berarti) . Saya pernah mendengar TAU memiliki kemampuan yang serupa.
sumber
Ini adalah dua metode yang saya gunakan untuk mempercepat kode saya:
Untuk aplikasi yang terikat CPU:
Untuk aplikasi terikat I / O:
NB
Jika Anda tidak memiliki profiler, gunakan profiler orang miskin itu. Hit jeda saat debug aplikasi Anda. Sebagian besar suite pengembang akan bergabung dengan nomor baris yang dikomentari. Secara statistik Anda cenderung mendarat di wilayah yang mengonsumsi sebagian besar siklus CPU Anda.
Untuk CPU, alasan untuk membuat profil dalam mode DEBUG adalah karena jika Anda mencoba membuat profil dalam mode RELEASE , kompiler akan mengurangi matematika, loop vektorisasi, dan fungsi sebaris yang cenderung menggumpal kode Anda menjadi kekacauan yang tidak dapat dipetakan ketika dirakit. Kekacauan yang tidak dapat dipetakan berarti profiler Anda tidak akan dapat dengan jelas mengidentifikasi apa yang perlu waktu lama karena perakitan mungkin tidak sesuai dengan kode sumber yang sedang dioptimalkan . Jika Anda memerlukan kinerja (misalnya sensitif terhadap waktu) dari mode RELEASE , nonaktifkan fitur debugger yang diperlukan untuk menjaga kinerja yang dapat digunakan.
Untuk I / O-terikat, profiler masih dapat mengidentifikasi operasi I / O dalam mode RELEASE karena operasi I / O terkait secara eksternal dengan perpustakaan bersama (sebagian besar waktu) atau dalam kasus terburuk, akan menghasilkan sistem panggil vektor interupsi (yang juga mudah diidentifikasi oleh profiler).
sumber
Anda dapat menggunakan perpustakaan iprof:
https://gitlab.com/Neurochrom/iprof
https://github.com/Neurochrom/iprof
Ini lintas platform dan memungkinkan Anda untuk tidak mengukur kinerja aplikasi Anda juga secara real-time. Anda bahkan dapat memasangkannya dengan grafik langsung. Penafian penuh: Saya adalah penulis.
sumber
Anda dapat menggunakan kerangka kerja pencatatan seperti
loguru
karena ia menyertakan cap waktu dan total waktu kerja yang dapat digunakan dengan baik untuk membuat profil:sumber
Di tempat kerja kami memiliki alat yang sangat bagus yang membantu kami memantau apa yang kami inginkan dalam hal penjadwalan. Ini telah berguna beberapa kali.
Ini dalam C ++ dan harus disesuaikan dengan kebutuhan Anda. Sayangnya saya tidak bisa membagikan kode, hanya konsep. Anda menggunakan
volatile
buffer "besar" yang berisi cap waktu dan ID aktivitas yang dapat Anda buang post mortem atau setelah menghentikan sistem logging (dan misalnya, membuangnya ke file).Anda mengambil buffer yang disebut besar dengan semua data dan antarmuka kecil mem-parsingnya dan menampilkan peristiwa dengan nama (nilai naik / turun) seperti osiloskop dengan warna (dikonfigurasi dalam
.hpp
file).Anda menyesuaikan jumlah acara yang dihasilkan untuk fokus hanya pada apa yang Anda inginkan. Ini banyak membantu kami untuk masalah penjadwalan sambil mengonsumsi jumlah CPU yang kami inginkan berdasarkan jumlah peristiwa yang dicatat per detik.
Anda membutuhkan 3 file:
Konsepnya adalah untuk mendefinisikan peristiwa
tool_events_id.hpp
seperti itu:Anda juga mendefinisikan beberapa fungsi di
toolname.hpp
:Di mana pun dalam kode Anda, Anda dapat menggunakan:
The
probe
fungsi menggunakan beberapa lini perakitan untuk mengambil jam timestamp ASAP dan kemudian menetapkan entri dalam buffer. Kami juga memiliki peningkatan atom untuk menemukan indeks tempat penyimpanan log dengan aman. Tentu saja buffer berbentuk lingkaran.Semoga idenya tidak dikaburkan oleh kurangnya kode sampel.
sumber
Sebenarnya sedikit terkejut tidak banyak disebutkan tentang google / benchmark , sementara itu agak rumit untuk menyematkan area kode tertentu, khususnya jika basis kode sedikit besar, namun saya menemukan ini sangat membantu ketika digunakan dalam kombinasi dengan
callgrind
IMHO mengidentifikasi bagian yang menyebabkan kemacetan adalah kuncinya di sini. Namun saya akan mencoba dan menjawab pertanyaan-pertanyaan berikut terlebih dahulu dan memilih alat berdasarkan itu
valgrind
dengan kombinasicallrind
dankcachegrind
harus memberikan estimasi yang layak pada poin-poin di atas dan setelah itu ditetapkan bahwa ada masalah dengan beberapa bagian kode, saya sarankan melakukan micro bench markgoogle benchmark
adalah tempat yang baik untuk memulai.sumber
Gunakan
-pg
bendera saat mengkompilasi dan menautkan kode dan menjalankan file yang dapat dieksekusi. Saat program ini dijalankan, profiling data dikumpulkan dalam file a.out.Ada dua jenis profil yang berbeda
1- Profil datar:
dengan menjalankan perintah,
gprog --flat-profile a.out
Anda mendapatkan data berikut- berapa persen dari keseluruhan waktu yang dihabiskan untuk fungsi,
- berapa detik yang dihabiskan dalam suatu fungsi — termasuk dan tidak termasuk panggilan ke subfungsi,
- jumlah panggilan,
- waktu rata-rata per panggilan.
2 - grafik profiling
kita perintah
gprof --graph a.out
untuk mendapatkan data berikut untuk setiap fungsi yang meliputi- Di setiap bagian, satu fungsi ditandai dengan nomor indeks.
- Di atas fungsi, ada daftar fungsi yang memanggil fungsi.
- Fungsi di bawah ini, ada daftar fungsi yang dipanggil oleh fungsi.
Untuk mendapatkan info lebih lanjut, Anda dapat melihat di https://sourceware.org/binutils/docs-2.32/gprof/
sumber
Karena tidak ada yang menyebutkan Arm MAP, saya akan menambahkan secara pribadi saya telah berhasil menggunakan Peta ke profil program ilmiah C ++.
Arm MAP adalah profiler untuk kode C, C ++, Fortran, dan F90 yang paralel, multithreaded, atau tunggal. Ini memberikan analisis mendalam dan menentukan titik kemacetan ke baris sumber. Tidak seperti kebanyakan profiler, ini dirancang untuk dapat profil pthreads, OpenMP atau MPI untuk kode paralel dan berulir.
MAP adalah perangkat lunak komersial.
sumber
menggunakan perangkat lunak debug bagaimana mengidentifikasi di mana kode berjalan lambat?
hanya berpikir Anda memiliki hambatan saat Anda bergerak maka itu akan menurunkan kecepatan Anda
seperti itu pengulangan realokasi yang tidak diinginkan, buffer overflows, pencarian, kebocoran memori dll operasi mengkonsumsi lebih banyak daya eksekusi itu akan berpengaruh buruk terhadap kinerja kode, Pastikan untuk menambahkan -pg ke kompilasi sebelum membuat profil:
g++ your_prg.cpp -pg
ataucc my_program.cpp -g -pg
sesuai kompiler Andabelum mencobanya tetapi saya pernah mendengar hal-hal baik tentang google-perftools. Ini pasti patut dicoba.
valgrind --tool=callgrind ./(Your binary)
Ini akan menghasilkan file bernama gmon.out atau callgrind.out.x. Anda kemudian dapat menggunakan alat kcachegrind atau debugger untuk membaca file ini. Ini akan memberi Anda analisis grafis dari hal-hal dengan hasil seperti garis mana yang menghabiskan biaya.
aku pikir begitu
sumber