Depurar contra desempenho de lançamento

Eu encontrei o seguinte parágrafo:

“A configuração Debug vs. Release no IDE quando você compila seu código no Visual Studio não faz quase nenhuma diferença no desempenho… o código gerado é quase o mesmo. O compilador C # realmente não faz qualquer otimização. O compilador C # apenas cospe IL… e no tempo de execução é o JITer que faz toda a otimização. O JITer tem um modo de debugging / liberação e isso faz uma enorme diferença no desempenho. Mas isso não desativa se você executa a configuração de Debug ou Release do seu projeto, que as chaves estão desligadas 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 possa realmente provar isso?

Pesquisando ” C # debug vs desempenho de lançamento ” principalmente retorna resultados dizendo ” Debug tem um monte de desempenho “, “o lançamento é otimizado ” e ” não implantar debugging para produção “.

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

  • variables ​​não utilizadas não são compiladas
  • algumas variables ​​de loop são retiradas do loop pelo compilador se forem provadas como invariantes
  • código escrito sob a diretiva #debug não está incluído etc.

O resto depende do JIT.

Edit: Lista completa de otimizações aqui cortesia de Eric Lippert

Não há nenhum artigo que “prove” alguma coisa sobre uma questão de desempenho. A maneira de provar uma afirmação sobre o impacto no desempenho de uma mudança é tentar de ambas as maneiras e testá-la em condições realistas, mas controladas.

Você está fazendo uma pergunta sobre desempenho, então claramente você se preocupa com o desempenho. Se você se preocupa com o desempenho, a melhor coisa a fazer é definir algumas metas de desempenho e, em seguida, criar uma suíte de testes que monitore seu progresso em relação a essas metas. Uma vez que você tenha uma suíte de teste, você pode facilmente usá-la para testar a verdade ou a falsidade de declarações como “a compilation de debugging é mais lenta”.

E além disso, você será capaz de 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 sob condições realistas” é mais significativo.

Gastar o tempo que você gastaria pesquisando esta questão on-line na construção de um dispositivo que responde à pergunta. Você obterá resultados muito mais precisos dessa maneira. Qualquer coisa que você leia online é apenas um palpite sobre o que pode acontecer. Razão dos fatos que você coletou, não dos palpites de outras pessoas sobre como seu programa pode se comportar.

Não posso comentar sobre o desempenho, mas o conselho “não implemente debugging para produção” ainda é válido porque o código de debugging geralmente faz algumas coisas de maneira diferente em produtos grandes. Por um lado, você pode ter comutadores de debugging ativos e, para outro, provavelmente haverá verificações de sanidade redundantes adicionais e saídas de debugging que não pertencem ao código de produção.

De msdn social

Não está bem documentado, aqui está o que eu sei. O compilador emite uma instância do System.Diagnostics.DebuggableAttribute. Na versão de debugging, 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 desabilitar otimizações que tornariam a debugging difícil. Os que movem o código como um içamento invariante de loop. Em casos selecionados, isso pode fazer uma grande diferença no desempenho. Geralmente não embora.

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

Basicamente, a implementação de debugging será mais lenta, pois as otimizações do compilador JIT estão desativadas.

O que você lê é bastante válido. O release geralmente é mais enxuto devido à otimização JIT, não incluindo o código de debugging (#IF DEBUG ou [Conditional (“DEBUG”)]), o carregamento de símbolo de debugging mínimo e muitas vezes não considerado é um assembly menor que reduz o tempo de carregamento. O desempenho diferente é mais óbvio ao executar o código no VS devido ao PDB mais extenso e aos símbolos que são carregados, mas se você executá-lo independentemente, as diferenças de desempenho podem ser menos aparentes. Determinado código otimizará melhor que outros e está usando as mesmas heurísticas de otimização como em outros idiomas.

Scott tem uma boa explicação sobre otimização de methods inline aqui

Veja este artigo que dá uma breve explicação porque é diferente no ambiente ASP.NET para debugging e configuração de lançamento.

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

Nós tínhamos um pedaço de código, envolvendo muitos loops apertados, que demoravam uma eternidade para ser depurados, mas funcionavam muito bem por conta própria. Em outras palavras, nenhum cliente ou cliente enfrentava problemas, mas, quando estávamos depurando, ele parecia funcionar como um melaço.

O culpado foi um Debug.WriteLine em um dos loops apertados, que cuspiu milhares de mensagens de log, deixadas de uma session de debugging um tempo atrás. Parece que quando o depurador é anexado e ouve essa saída, há sobrecarga envolvida que atrasa o programa. Para esse código específico, ele estava na ordem de 0,2 a 0,3 segundo de tempo de execução sozinho e mais de 30 segundos quando o depurador estava conectado.

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

No site msdn …

Configurações de lançamento vs. debugging

Enquanto você ainda está trabalhando em seu projeto, normalmente você construirá seu aplicativo usando a configuração de debugging, porque essa configuração permite visualizar o valor de variables ​​e controlar a execução no depurador. Você também pode criar e testar compilações na configuração do release para garantir que você não tenha introduzido nenhum erro que se manifesta apenas em um tipo de compilation ou outro. Na programação do .NET Framework, esses bugs são muito raros, mas podem ocorrer.

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

Eu recentemente me deparo com um problema de desempenho. A lista completa de produtos estava demorando muito tempo, cerca de 80 segundos. Afinei o DB, melhorei as consultas e não houve diferença. Eu decidi criar um TestProject e descobri que o mesmo processo foi executado em 4 segundos. Então percebi que o projeto estava no modo de debugging 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 debugging é muito mais lento que o modo de execução, pois mantém as informações de debugging. Você deve sempre implantar no modo Relase. Você ainda pode ter informações de debugging se você include arquivos .PDB. Dessa forma, você pode registrar erros com números de linha, por exemplo.

Em grande medida, isso depende de o seu aplicativo estar ligado à computação e nem sempre é fácil dizer, como no exemplo de Lasse. Se eu tenho a menor dúvida sobre o que está fazendo, paro algumas vezes e examino a pilha. Se há algo extra acontecendo que eu realmente não precisei, isso aparece imediatamente.

Os modos de debugging e liberação possuem diferenças. Existe uma ferramenta Fuzzlyn : é um fuzzer que utiliza Roslyn para gerar programas C # randoms. Ele executa esses programas no núcleo .NET e garante que eles forneçam os mesmos resultados quando compilados no modo de debugging e liberação.

Com esta ferramenta foi encontrado e reportado um monte de bugs.