Prestazioni di debug vs. rilascio


132

Ho riscontrato il seguente paragrafo:

“L'impostazione Debug vs. Release nell'IDE quando compili il codice in Visual Studio non fa quasi alcuna differenza per le prestazioni ... il codice generato è quasi lo stesso. Il compilatore C # non fa davvero alcuna ottimizzazione. Il compilatore C # sputa semplicemente IL ... e in fase di esecuzione è il JITer che esegue tutta l'ottimizzazione. Il JITer ha una modalità Debug / Release e questo fa una grande differenza nelle prestazioni. Ma ciò non toglie se esegui la configurazione Debug o Release del tuo progetto, ciò toglie se è collegato un debugger. "

La fonte è qui e il podcast è qui .

Qualcuno può indirizzarmi a un articolo di Microsoft che può effettivamente dimostrarlo?

Googling " Debug C # vs prestazioni di rilascio " restituisce principalmente risultati che dicono "Il debug ha molto successo ", "il rilascio è ottimizzato " e " non distribuire il debug alla produzione ".


possibile duplicato delle differenze
Hans Passant

Con .Net4 su Win7-x86, ho un programma limitato alla CPU che ho scritto che esegue quasi 2 volte più velocemente in rilascio rispetto al debug senza assert / etc nel ciclo principale.
Bengie,

Inoltre, se ti interessa l'utilizzo della memoria, possono esserci grandi differenze. Ho visto un caso in cui un servizio Windows multi-thread compilato in modalità Debug utilizzava 700 MB per thread, rispetto a 50 MB per thread nella build di rilascio. La build di debug ha esaurito rapidamente la memoria in condizioni di utilizzo tipiche.
o. nate

@Bengie - hai verificato che se colleghi un debugger alla build di rilascio, funziona ancora 2 volte più veloce? Si noti che la citazione sopra dice che l'ottimizzazione JIT è influenzata dal fatto che il debugger sia collegato.
ToolmakerSteve

Risposte:


99

Parzialmente vero. In modalità debug, il compilatore emette simboli di debug per tutte le variabili e compila il codice così com'è. Nella modalità di rilascio sono incluse alcune ottimizzazioni:

  • le variabili non utilizzate non vengono affatto compilate
  • alcune variabili del ciclo vengono estratte dal ciclo dal compilatore se si dimostrano invarianti
  • il codice scritto sotto la direttiva #debug non è incluso, ecc.

Il resto spetta alla squadra.

Elenco completo di ottimizzazioni qui per gentile concessione di Eric Lippert .


10
E non dimenticare Debug.Asserts! Nella build DEBUG, se falliscono, interromperanno il thread e apriranno una finestra di messaggio. In rilascio non vengono compilati affatto. Questo vale per tutti i metodi che hanno [ConditionalAttribute].
Ivan Zlatanov,

13
Il compilatore C # non esegue ottimizzazioni delle chiamate di coda; lo fa il jitter. Se si desidera un elenco accurato di ciò che fa il compilatore C # quando l'interruttore di ottimizzazione è attivato
Eric Lippert

63

Non esiste un articolo che "provi" qualcosa su una domanda di performance. Il modo per dimostrare un'affermazione sull'impatto delle prestazioni di un cambiamento è provarlo in entrambi i modi e testarlo in condizioni realistiche ma controllate.

Stai ponendo una domanda sulle prestazioni, quindi chiaramente ti preoccupi delle prestazioni. Se ti preoccupi delle prestazioni, la cosa giusta da fare è fissare alcuni obiettivi prestazionali e quindi scrivere una suite di test che tenga traccia dei tuoi progressi rispetto a tali obiettivi. Una volta che hai una tale suite di test, puoi facilmente usarla per testare la verità o la falsità di affermazioni come "la build del debug è più lenta".

Inoltre, sarai in grado di ottenere risultati significativi. "Più lento" non ha senso perché non è chiaro se è un microsecondo più lento o venti minuti più lento. "Il 10% più lento in condizioni realistiche" è più significativo.

Trascorri il tempo che avresti dedicato alla ricerca online di questa domanda per costruire un dispositivo che risponda alla domanda. In questo modo otterrai risultati molto più precisi. Tutto ciò che leggi online è solo un'ipotesi di cosa potrebbe accadere. Motivo dai fatti raccolti, non dalle ipotesi di altre persone su come potrebbe comportarsi il programma.


2
Penso che ti possa interessare le prestazioni ma hai ancora il desiderio di usare "debug". Ad esempio, se la maggior parte del tempo è in attesa di dipendenze, non credo che la creazione in modalità debug farà una grande differenza, ma hai il vantaggio aggiuntivo di ottenere i numeri di riga nelle tracce dello stack, il che può aiutare a correggere i bug più velocemente e rendere utenti più felici. Il punto è che devi valutare i pro e i contro e un'affermazione generale "eseguire il debug è più lenta, ma solo se sei vincolato alla CPU" è sufficiente per aiutarti nella decisione.
Josh Mouch,

11

Non posso commentare le prestazioni, ma il consiglio "non distribuire il debug alla produzione" è ancora valido perché il codice di debug di solito fa diverse cose in modo diverso nei prodotti di grandi dimensioni. Per prima cosa, potresti avere switch di debug attivi e per un altro ci saranno probabilmente ulteriori controlli di integrità ridondanti e output di debug che non appartengono al codice di produzione.


Sono d'accordo con te su questo problema, ma questo non risponde alla domanda principale
sagie

5
@sagie: si, ne sono consapevole ma ho pensato che valesse la pena di chiarire il punto.
Konrad Rudolph,

6

Da msdn social

Non è ben documentato, ecco quello che so. Il compilatore emette un'istanza di System.Diagnostics.DebuggableAttribute. Nella versione di debug, la proprietà IsJitOptimizerEnabled è True, nella versione di rilascio è False. È possibile visualizzare questo attributo nel manifest dell'assembly con ildasm.exe

Il compilatore JIT utilizza questo attributo per disabilitare le ottimizzazioni che renderebbero difficile il debug. Quelli che spostano il codice come un sollevamento invariante in loop. In alcuni casi, ciò può fare una grande differenza nelle prestazioni. Di solito però no.

Il mapping dei punti di interruzione agli indirizzi di esecuzione è il compito del debugger. Utilizza il file .pdb e le informazioni generate dal compilatore JIT che fornisce l'istruzione IL per codificare il mapping degli indirizzi. Se dovessi scrivere il tuo debugger, utilizzeresti ICorDebugCode :: GetILToNativeMapping ().

Fondamentalmente il debug della distribuzione sarà più lento poiché le ottimizzazioni del compilatore JIT sono disabilitate.


3

Quello che leggi è abbastanza valido. Il rilascio è in genere più snello a causa dell'ottimizzazione JIT, ad esclusione del codice di debug (#IF DEBUG o [Condizionale ("DEBUG")]), il caricamento minimo del simbolo di debug e spesso non considerato è un assemblaggio più piccolo che ridurrà il tempo di caricamento. Le prestazioni diverse sono più evidenti quando si esegue il codice in VS a causa del PDB più ampio e dei simboli caricati, ma se lo si esegue in modo indipendente, le differenze di prestazioni potrebbero essere meno evidenti. Determinato codice ottimizzerà meglio di altri e utilizza la stessa euristica di ottimizzazione proprio come in altre lingue.

Scott ha una buona spiegazione sull'ottimizzazione del metodo in linea qui

Vedi questo articolo che fornisce una breve spiegazione del perché è diverso nell'ambiente ASP.NET per le impostazioni di debug e rilascio.


3

Una cosa che dovresti notare, per quanto riguarda le prestazioni e se il debugger è collegato o meno, qualcosa che ci ha sorpreso.

Avevamo un pezzo di codice, che includeva molti loop stretti, che sembrava richiedere del tempo per eseguire il debug, ma funzionava abbastanza bene da solo. In altre parole, nessun cliente o cliente dove si sono verificati problemi, ma quando stavamo eseguendo il debug sembrava funzionare come melassa.

Il colpevole era Debug.WriteLinein uno dei loop stretti, che sputavano fuori migliaia di messaggi di log, lasciati da una sessione di debug qualche tempo fa. Sembra che quando il debugger è collegato e ascolta tale output, c'è un sovraccarico che rallenta il programma. Per questo particolare codice, era nell'ordine di 0,2-0,3 secondi di autonomia e 30+ secondi quando il debugger era collegato.

Soluzione semplice, basta rimuovere i messaggi di debug che non erano più necessari.


2

Nel sito msdn ...

Configurazioni Release vs Debug

Mentre stai ancora lavorando al tuo progetto, in genere costruirai l'applicazione utilizzando la configurazione di debug, poiché questa configurazione ti consente di visualizzare il valore delle variabili e controllare l'esecuzione nel debugger. Puoi anche creare e testare build nella configurazione di rilascio per assicurarti di non aver introdotto alcun bug che si manifesta solo su un tipo di build o sull'altro. Nella programmazione .NET Framework, tali bug sono molto rari, ma possono verificarsi.

Quando sei pronto a distribuire la tua applicazione agli utenti finali, crea una build di rilascio, che sarà molto più piccola e di solito avrà prestazioni molto migliori rispetto alla corrispondente configurazione di debug. È possibile impostare la configurazione di compilazione nel riquadro Build di Project Designer o nella barra degli strumenti Build. Per ulteriori informazioni, consultare Build Configurations.


1

In larga misura, ciò dipende dal fatto che l'app sia legata al calcolo, e non è sempre facile da dire, come nell'esempio di Lasse. Se ho la minima domanda su cosa stia facendo, lo metto in pausa alcune volte ed esamino lo stack. Se sta succedendo qualcosa in più di cui non ho davvero bisogno, lo individua immediatamente.


1

Di recente ho riscontrato un problema di prestazioni. L'elenco completo dei prodotti impiegava troppo tempo, circa 80 secondi. Ho ottimizzato il DB, migliorato le query e non c'erano differenze. Ho deciso di creare un TestProject e ho scoperto che lo stesso processo è stato eseguito in 4 secondi. Quindi ho realizzato che il progetto era in modalità Debug e il progetto di test era in modalità Rilascio. Ho passato il progetto principale in modalità Rilascio e l'elenco completo dei prodotti ha richiesto solo 4 secondi per visualizzare tutti i risultati.

Riepilogo: la modalità di debug è molto più lenta della modalità di esecuzione poiché mantiene le informazioni di debug. È necessario distribuire sempre in modalità Relase. Puoi comunque avere informazioni di debug se includi file .PDB. In questo modo è possibile registrare errori con numeri di riga, ad esempio.


Per "modalità di esecuzione" intendi "Rilascio"?
Ron Klein,

Si, esattamente. Il rilascio non ha tutto l'overhead di debug.
Francisco Goldenstein,

1

Le modalità di debug e rilascio presentano differenze. C'è uno strumento Fuzzlyn : è un fuzzer che utilizza Roslyn per generare programmi casuali C #. Esegue questi programmi su .NET core e garantisce che forniscano gli stessi risultati quando vengono compilati in modalità debug e release.

Con questo strumento è stato trovato e segnalato molti bug.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.