Debug vs. Kinerja rilis

132

Saya telah menemukan paragraf berikut:

“Pengaturan Debug vs. Release di IDE ketika Anda mengkompilasi kode Anda di Visual Studio membuat hampir tidak ada perbedaan untuk kinerja ... kode yang dihasilkan hampir sama. Compiler C # tidak benar-benar melakukan optimasi. Compiler C # hanya memuntahkan IL ... dan pada saat runtime itu adalah JITer yang melakukan semua optimasi. JITer memang memiliki mode Debug / Release dan itu membuat perbedaan besar untuk kinerja. Tetapi itu tidak berarti apakah Anda menjalankan konfigurasi Debug atau Release proyek Anda, itu mematikan apakah debugger dilampirkan. "

Sumbernya ada di sini dan podcast ada di sini .

Bisakah seseorang mengarahkan saya ke artikel Microsoft yang benar-benar dapat membuktikan ini?

Googling " C # debug vs rilis kinerja " sebagian besar mengembalikan hasil yang mengatakan " Debug memiliki banyak hit kinerja ", " rilis dioptimalkan ", dan " jangan gunakan debug untuk produksi ".

sagie
sumber
kemungkinan duplikat perbedaan Kinerja antara debug dan rilis build
Hans Passant
Dengan .Net4 pada Win7-x86, saya memiliki program terbatas CPU yang saya tulis yang berjalan hampir 2x lebih cepat dalam rilis daripada debug tanpa menegaskan / etc di loop utama.
Bengie
Juga, jika Anda peduli tentang penggunaan memori, mungkin ada perbedaan besar. Saya telah melihat kasus di mana layanan Windows multi-threaded dikompilasi dalam mode Debug menggunakan 700MB per utas, vs 50MB per utas dalam rilis Release. Debug build cepat kehabisan memori dalam kondisi penggunaan umum.
o. nate
@ Bengie - apakah Anda memverifikasi bahwa jika Anda melampirkan debugger ke rilis rilis, masih berjalan 2x lebih cepat? Perhatikan bahwa kutipan di atas mengatakan bahwa optimasi JIT dipengaruhi oleh apakah debugger dilampirkan.
ToolmakerSteve

Jawaban:

99

Sebagian benar. Dalam mode debug, kompiler memancarkan simbol debug untuk semua variabel dan mengkompilasi kode apa adanya. Dalam mode rilis, beberapa optimasi disertakan:

  • variabel yang tidak digunakan tidak bisa dikompilasi sama sekali
  • beberapa variabel loop dikeluarkan dari loop oleh kompiler jika mereka terbukti invarian
  • kode yang ditulis di bawah arahan #debug tidak termasuk, dll.

Sisanya terserah JIT.

Daftar lengkap optimasi di sini adalah milik Eric Lippert .

Adrian Zanescu
sumber
10
Dan jangan lupa tentang Debug. Masukkan! Di DEBUG build, jika gagal, mereka akan menghentikan utas dan memunculkan kotak pesan. Dalam rilis mereka tidak dikompilasi sama sekali. Ini berlaku untuk semua metode yang memiliki [ConditionalAttribute].
Ivan Zlatanov
13
Kompiler C # tidak melakukan optimasi panggilan ekor; jitter tidak. Jika Anda ingin daftar akurat tentang apa yang dilakukan oleh kompiler C # ketika sakelar optimisasi diaktifkan, lihat blogs.msdn.com/ericlippert/archive/2009/06/11/…
Eric Lippert
63

Tidak ada artikel yang "membuktikan" apa pun tentang pertanyaan kinerja. Cara untuk membuktikan pernyataan tentang dampak kinerja dari perubahan adalah dengan mencoba keduanya dan mengujinya di bawah kondisi yang realistis namun terkendali.

Anda mengajukan pertanyaan tentang kinerja, jadi jelas Anda peduli dengan kinerja. Jika Anda peduli dengan kinerja maka hal yang benar untuk dilakukan adalah menetapkan beberapa sasaran kinerja dan kemudian menulis sendiri rangkaian uji yang melacak kemajuan Anda terhadap sasaran-sasaran itu. Setelah Anda memiliki test suite seperti itu, Anda dapat dengan mudah menggunakannya untuk menguji kebenaran atau kesalahan pernyataan seperti "debug build lebih lambat".

Dan selanjutnya, Anda akan bisa mendapatkan hasil yang bermakna. "Lebih lambat" tidak ada artinya karena tidak jelas apakah itu satu mikrodetik lebih lambat atau dua puluh menit lebih lambat. "10% lebih lambat dalam kondisi realistis" lebih bermakna.

Luangkan waktu yang Anda habiskan untuk meneliti pertanyaan ini secara online untuk membuat perangkat yang menjawab pertanyaan. Anda akan mendapatkan hasil yang jauh lebih akurat dengan cara itu. Apa pun yang Anda baca online hanyalah tebakan tentang apa yang mungkin terjadi. Alasan dari fakta yang Anda kumpulkan sendiri, bukan dari dugaan orang lain tentang bagaimana program Anda mungkin berperilaku.

Eric Lippert
sumber
2
Saya pikir Anda dapat peduli tentang kinerja namun masih memiliki keinginan untuk menggunakan "debug". Misalnya, jika sebagian besar waktu Anda menunggu dependensi, saya tidak berpikir membangun dalam mode debug akan membuat perbedaan besar, namun Anda memiliki manfaat tambahan untuk mendapatkan nomor baris dalam jejak tumpukan, yang dapat membantu memperbaiki bug lebih cepat dan membuat pengguna yang lebih bahagia. Intinya adalah Anda harus mempertimbangkan pro dan kontra, dan pernyataan umum "berjalan dalam debug lebih lambat, tetapi hanya jika Anda terikat CPU" sudah cukup untuk membantu dengan keputusan.
Josh Mouch
11

Saya tidak dapat mengomentari kinerja tetapi saran "jangan gunakan debug untuk produksi" masih berlaku hanya karena kode debug biasanya melakukan beberapa hal berbeda secara berbeda dalam produk besar. Untuk satu hal, Anda mungkin memiliki sakelar debug aktif dan untuk yang lain mungkin akan ada tambahan pemeriksaan kewarasan berlebihan dan hasil debug yang tidak termasuk dalam kode produksi.

Konrad Rudolph
sumber
Saya setuju dengan Anda tentang masalah itu, tetapi ini tidak menjawab pertanyaan utama
sagie
5
@sagie: ya, saya sadar akan hal itu tetapi saya pikir intinya masih layak dibuat.
Konrad Rudolph
6

Dari msdn social

Tidak terdokumentasi dengan baik, inilah yang saya tahu. Kompiler memancarkan instance dari System.Diagnostics.DebuggableAttribute. Dalam versi debug, properti IsJitOptimizerEnabled adalah Benar, dalam versi rilis itu False. Anda dapat melihat atribut ini di manifes perakitan dengan ildasm.exe

Kompiler JIT menggunakan atribut ini untuk menonaktifkan optimasi yang akan membuat proses debug sulit. Orang-orang yang memindahkan kode seperti mengangkat loop-invarian. Dalam kasus tertentu, ini dapat membuat perbedaan besar dalam kinerja. Tapi biasanya tidak.

Memetakan breakpoint ke alamat eksekusi adalah tugas debugger. Ia menggunakan file .pdb dan info yang dihasilkan oleh kompiler JIT yang menyediakan instruksi IL untuk pemetaan alamat kode. Jika Anda akan menulis debugger Anda sendiri, Anda akan menggunakan ICorDebugCode :: GetILToNativeMapping ().

Pada dasarnya penerapan debug akan lebih lambat karena optimisasi kompiler JIT dinonaktifkan.

Neil
sumber
3

Apa yang Anda baca cukup valid. Rilis biasanya lebih ramping karena optimasi JIT, tidak termasuk kode debug (#IF DEBUG atau [Conditional ("DEBUG")]), pemuatan simbol debug minimal dan sering tidak dianggap sebagai perakitan kecil yang akan mengurangi waktu pemuatan. Perbedaan kinerja lebih jelas ketika menjalankan kode dalam VS karena PDB lebih luas dan simbol yang dimuat, tetapi jika Anda menjalankannya secara independen, perbedaan kinerja mungkin kurang jelas. Kode tertentu akan mengoptimalkan lebih baik daripada yang lain dan menggunakan heuristik optimisasi yang sama seperti dalam bahasa lain.

Scott memiliki penjelasan yang bagus tentang pengoptimalan metode inline di sini

Lihat artikel ini yang memberikan penjelasan singkat mengapa berbeda di lingkungan ASP.NET untuk pengaturan debug dan rilis.

Fadrian Sudaman
sumber
3

Satu hal yang harus Anda perhatikan, mengenai kinerja dan apakah debugger terpasang atau tidak, sesuatu yang mengejutkan kami.

Kami memiliki sepotong kode, yang melibatkan banyak loop ketat, yang sepertinya membutuhkan waktu lama untuk debug, namun berjalan dengan baik. Dengan kata lain, tidak ada pelanggan atau klien yang mengalami masalah, tetapi ketika kami melakukan debug, sepertinya berjalan seperti molase.

Pelakunya adalah Debug.WriteLinedi salah satu loop ketat, yang memuntahkan ribuan pesan log, meninggalkan sesi debug beberapa waktu lalu. Tampaknya ketika debugger dilampirkan dan mendengarkan output seperti itu, ada overhead yang terlibat yang memperlambat program. Untuk kode khusus ini, ia berada pada urutan 0,2-0,3 detik runtime sendiri, dan 30+ detik ketika debugger dilampirkan.

Namun solusi sederhana, cukup hapus pesan debug yang tidak lagi diperlukan.

Lasse V. Karlsen
sumber
2

Di situs msdn ...

Rilis vs. konfigurasi Debug

Saat Anda masih mengerjakan proyek Anda, Anda biasanya akan membangun aplikasi Anda dengan menggunakan konfigurasi debug, karena konfigurasi ini memungkinkan Anda untuk melihat nilai variabel dan mengontrol eksekusi di debugger. Anda juga dapat membuat dan menguji build dalam konfigurasi rilis untuk memastikan bahwa Anda belum memperkenalkan bug apa pun yang hanya bermanifestasi pada satu tipe build atau yang lainnya. Dalam pemrograman .NET Framework, bug semacam itu sangat jarang, tetapi dapat terjadi.

Ketika Anda siap untuk mendistribusikan aplikasi Anda ke pengguna akhir, buat rilis rilis, yang akan jauh lebih kecil dan biasanya akan memiliki kinerja yang jauh lebih baik daripada konfigurasi debug yang sesuai. Anda bisa mengatur konfigurasi build di panel Build dari Project Designer, atau di toolbar Build. Untuk informasi lebih lanjut, lihat Membangun Konfigurasi.

Hallie
sumber
1

Sebagian besar, itu tergantung pada apakah aplikasi Anda terikat komputasi, dan tidak selalu mudah untuk mengatakannya, seperti dalam contoh Lasse. Jika saya punya pertanyaan sekecil apa tentang apa yang dilakukannya, saya berhenti sebentar dan memeriksa tumpukan. Jika ada sesuatu yang terjadi ekstra yang tidak saya butuhkan, itu akan langsung terlihat.

Mike Dunlavey
sumber
1

Saya baru-baru ini mengalami masalah kinerja. Daftar lengkap produk terlalu banyak waktu, sekitar 80 detik. Saya menyetel DB, meningkatkan kueri dan tidak ada perbedaan. Saya memutuskan untuk membuat TestProject dan saya menemukan bahwa proses yang sama dijalankan dalam 4 detik. Kemudian saya menyadari proyek dalam mode Debug dan proyek uji dalam mode Rilis. Saya mengalihkan proyek utama ke mode Rilis dan daftar lengkap produk hanya membutuhkan waktu 4 detik untuk menampilkan semua hasil.

Rangkuman: Mode debug jauh lebih lambat daripada mode lari karena mode ini menjaga informasi debug. Anda harus selalu menggunakan mode Relase. Anda masih dapat memiliki informasi debug jika Anda menyertakan file .PDB. Dengan begitu Anda dapat mencatat kesalahan dengan nomor baris, misalnya.

Francisco Goldenstein
sumber
Dengan "menjalankan mode" yang Anda maksud "Lepaskan"?
Ron Klein
Ya persis. Rilis tidak memiliki semua overhead debug.
Francisco Goldenstein
1

Mode debug dan rilis memiliki perbedaan. Ada alat Fuzzlyn : ini adalah fuzzer yang memanfaatkan Roslyn untuk menghasilkan program C # acak. Ini menjalankan program-program ini pada .NET core dan memastikan bahwa mereka memberikan hasil yang sama ketika dikompilasi dalam mode debug dan rilis.

Dengan alat ini ditemukan dan dilaporkan banyak bug.

Sergey Ponomarev
sumber