Desempenho de depuração vs. versão


132

Encontrei o seguinte parágrafo:

“A configuração Debug vs. Release no IDE quando você compila seu código no Visual Studio quase não faz diferença para o desempenho ... o código gerado é quase o mesmo. O compilador C # realmente não faz nenhuma otimização. O compilador C # apenas cita IL… e, no tempo de execução, é o JITer que faz toda a otimização. O JITer possui um modo de Depuração / Liberação e isso faz uma enorme diferença no desempenho. Mas isso não indica se você executa a configuração Debug ou Release do seu projeto, mas indica se um depurador está conectado. ”

A fonte está aqui e o podcast está aqui .

Alguém pode me direcionar para um artigo da Microsoft que pode realmente provar isso?

A pesquisa no Google sobre " desempenho de depuração vs versão C # " retorna principalmente resultados dizendo "A depuração tem muito impacto no desempenho ", " versão otimizada " e " não implantar depuração na produção ".



Com o .Net4 no Win7-x86, tenho um programa limitado de CPU que escrevi que roda quase duas vezes mais rápido do que o debug sem assert / etc no loop principal.
Bengie 14/05

Além disso, se você se preocupa com o uso da memória, pode haver grandes diferenças. Eu vi um caso em que um serviço Windows multithread compilado no modo Debug usava 700 MB por thread, contra 50 MB por thread na versão. A compilação Debug ficou sem memória rapidamente em condições típicas de uso.
o. nate

@ Bengie - você verificou que, se anexar um depurador à versão, ele ainda será executado 2x mais rápido? Observe que a citação acima diz que a otimização do JIT é afetada pelo fato de o depurador estar anexado.
precisa

Respostas:


99

Parcialmente verdade. No modo de depuração, o compilador emite símbolos de depuração para todas as variáveis ​​e compila o código como está. No modo de liberação, algumas otimizações estão incluídas:

  • variáveis ​​não utilizadas não são compiladas
  • algumas variáveis ​​de loop são retiradas do loop pelo compilador se for comprovadamente invariável
  • o código escrito sob a diretiva #debug não está incluído, etc.

O resto é com o JIT.

Lista completa de otimizações aqui, cortesia de Eric Lippert .


10
E não se esqueça do Debug.Asserts! Na compilação DEBUG, se falharem, interromperão o encadeamento e abrirão uma caixa de mensagem. Na versão, eles não são compilados. Isso se aplica a todos os métodos que possuem [ConditionalAttribute].
Ivan Zlatanov

13
O compilador C # não realiza otimizações de chamada de cauda; o jitter faz. Se você deseja uma lista precisa do que o compilador C # faz quando a opção de otimização está ativada
Eric Lippert

63

Não há artigo que "prove" algo sobre uma questão de desempenho. A maneira de provar uma afirmação sobre o impacto no desempenho de uma mudança é tentar dos dois lados e testá-lo sob condições realistas, mas controladas.

Você está fazendo uma pergunta sobre desempenho, tão claramente se importa com desempenho. Se você se preocupa com o desempenho, a coisa certa a fazer é definir algumas metas de desempenho e, em seguida, escrever um conjunto de testes que rastreie seu progresso em relação a essas metas. Depois de ter esse conjunto de testes, você poderá usá-lo facilmente para testar por si mesmo a verdade ou falsidade de declarações como "a compilação de depuração é mais lenta".

Além disso, você poderá obter resultados significativos. "Mais lento" não tem sentido porque não está claro se é um microssegundo mais lento ou vinte minutos mais lento. "10% mais lento em condições realistas" é mais significativo.

Gaste o tempo que você gastaria pesquisando essa pergunta on-line na criação de um dispositivo que responda à pergunta. Você obterá resultados muito mais precisos dessa maneira. Tudo o que você lê online é apenas um palpite sobre o que pode acontecer. Razão dos fatos que você coletou, não das suposições de outras pessoas sobre como seu programa pode se comportar.


2
Eu acho que você pode se preocupar com desempenho, mas ainda deseja usar "debug". Por exemplo, se a maior parte do seu tempo está aguardando dependências, não acho que a criação no modo de depuração faça uma grande diferença, mas você tem o benefício adicional de obter números de linha nos rastreamentos de pilha, o que pode ajudar a corrigir erros mais rapidamente usuários mais felizes. O ponto é que você precisa pesar os prós e os contras, e uma declaração geral "executando depuração é mais lenta, mas apenas se você estiver vinculado à CPU" é suficiente para ajudar na decisão.
Josh Mouch

11

Não posso comentar sobre o desempenho, mas o conselho "não implantar depuração na produção" ainda é válido porque o código de depuração geralmente faz algumas coisas de maneira diferente em produtos grandes. Por um lado, você pode ter os switches de depuração ativos e, por outro, provavelmente haverá verificações de integridade adicionais redundantes e saídas de depuração que não pertencem ao código de produção.


Concordo com você sobre essa questão, mas isso não responde à questão principal
Sagie

5
@ sagie: sim, eu estou ciente disso, mas pensei que ainda valia a pena esclarecer.
Konrad Rudolph

6

De msdn social

Não está bem documentado, eis o que eu sei. O compilador emite uma instância do System.Diagnostics.DebuggableAttribute. Na versão de depuração, a propriedade IsJitOptimizerEnabled é True, na versão de lançamento é False. Você pode ver esse atributo no manifesto do assembly com ildasm.exe

O compilador JIT usa esse atributo para desativar otimizações que dificultariam a depuração. Os que movem o código como uma elevação invariável por loop. Em casos selecionados, isso pode fazer uma grande diferença no desempenho. Normalmente não.

Mapear pontos de interrupção para endereços de execução é o trabalho do depurador. Ele usa o arquivo .pdb e as informações geradas pelo compilador JIT que fornece a instrução IL para codificar o mapeamento de endereços. Se você escrevesse seu próprio depurador, usaria ICorDebugCode :: GetILToNativeMapping ().

Basicamente, a implantação de depuração será mais lenta, pois as otimizações do compilador JIT estão desabilitadas.


3

O que você lê é bastante válido. A liberação geralmente é mais enxuta devido à otimização do JIT, não incluindo o código de depuração (#IF DEBUG ou [Condicional ("DEBUG")])), o carregamento mínimo do símbolo de depuração e muitas vezes não sendo considerado como um conjunto menor, o que reduzirá o tempo de carregamento. O desempenho diferente é mais óbvio ao executar o código no VS por causa do PDB e símbolos carregados mais extensos, mas se você executá-lo independentemente, as diferenças de desempenho podem ser menos aparentes. Certos códigos otimizarão melhor que outros e usarão as mesmas heurísticas de otimização, como em outros idiomas.

Scott tem uma boa explicação sobre otimização de método em linha aqui

Consulte este artigo que fornece uma breve explicação sobre por que é diferente no ambiente do ASP.NET para a configuração de depuração e lançamento.


3

Uma coisa que você deve observar, com relação ao desempenho e se o depurador está conectado ou não, algo que nos pegou de surpresa.

Tínhamos um código, envolvendo muitos loops apertados, que pareciam levar uma eternidade para depurar, mas funcionavam muito bem por conta própria. Em outras palavras, nenhum cliente ou cliente estava com problemas, mas quando estávamos depurando, parecia correr como melaço.

O culpado foi Debug.WriteLineum dos laços apertados, que emitiram milhares de mensagens de log, deixadas em uma sessão de depuração há um tempo. Parece que quando o depurador é anexado e ouve essa saída, há uma sobrecarga envolvida que atrasa o programa. Para esse código em particular, era da ordem de 0,2-0,3 segundos de execução por conta própria e mais de 30 segundos quando o depurador foi anexado.

Solução simples, basta remover as mensagens de depuração que não eram mais necessárias.


2

No site msdn ...

Configurações de versão vs. depuração

Enquanto você ainda estiver trabalhando em seu projeto, normalmente criará seu aplicativo usando a configuração de depuração, porque essa configuração permite exibir o valor das variáveis ​​e controlar a execução no depurador. Você também pode criar e testar compilações na configuração da versão para garantir que não introduziu nenhum erro que se manifeste apenas em um tipo de compilação ou no outro. Na programação do .NET Framework, esses erros são muito raros, mas podem ocorrer.

Quando você estiver pronto para distribuir seu aplicativo aos usuários finais, crie uma versão compilada, que será muito menor e normalmente terá um desempenho muito melhor que a configuração de depuração correspondente. Você pode definir a configuração de compilação no painel Compilar do Designer de Projeto ou na barra de ferramentas Compilar. Para mais informações, consulte Construir configurações.


1

Em grande medida, isso depende se o seu aplicativo é vinculado à computação e nem sempre é fácil saber, como no exemplo de Lasse. Se eu tenho a menor pergunta sobre o que está fazendo, paro algumas vezes e examino a pilha. Se há algo extra acontecendo que eu realmente não preciso, isso identifica imediatamente.


1

Recentemente, tive um problema de desempenho. A lista completa de produtos estava demorando muito, cerca de 80 segundos. Ajustei o banco de dados, aprimorei as consultas e não havia nenhuma diferença. Decidi criar um TestProject e descobri que o mesmo processo foi executado em 4 segundos. Então percebi que o projeto estava no modo Debug e o projeto de teste estava no modo Release. Mudei o projeto principal para o modo Release e a lista completa de produtos levou apenas 4 segundos para exibir todos os resultados.

Resumo: O modo de depuração é muito mais lento que o modo de execução, pois mantém as informações de depuração. Você sempre deve implantar no modo Relase. Você ainda pode ter informações de depuração se incluir arquivos .PDB. Dessa forma, você pode registrar erros com números de linha, por exemplo.


Por "modo de execução", você quer dizer "Liberar"?
Ron Klein

Sim, exatamente. A versão não possui toda a sobrecarga de depuração.
Francisco Goldenstein

1

Os modos de depuração e liberação têm diferenças. Existe uma ferramenta Fuzzlyn : é um fuzzer que utiliza Roslyn para gerar programas C # aleatórios. Ele executa esses programas no núcleo do .NET e garante que eles apresentem os mesmos resultados quando compilados no modo de depuração e liberação.

Com esta ferramenta, foi encontrado e relatado muitos bugs.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.