Rendimiento de depuración frente a lanzamiento

132

Me he encontrado con el siguiente párrafo:

“La configuración de depuración frente a lanzamiento en el IDE cuando compila su código en Visual Studio casi no hace ninguna diferencia en el rendimiento ... el código generado es casi el mismo. El compilador de C # realmente no hace ninguna optimización. El compilador de C # solo escupe IL ... y en el tiempo de ejecución es el JITer el que hace toda la optimización. El JITer tiene un modo de depuración / liberación y eso hace una gran diferencia en el rendimiento. Pero eso no elimina si ejecuta la configuración de Depuración o Liberación de su proyecto, eso desactiva si se adjunta un depurador ".

La fuente está aquí y el podcast está aquí .

¿Alguien puede dirigirme a un artículo de Microsoft que realmente pueda probar esto?

Buscar en Google " C # depuración vs rendimiento de la versión " en su mayoría devuelve resultados que dicen " Debug tiene mucho impacto en el rendimiento ", "la versión está optimizada " y " no implemente la depuración en producción ".

sagie
fuente
posible duplicado de las diferencias
Hans Passant
Con .Net4 en Win7-x86, tengo un programa limitado de CPU que escribí que se ejecuta casi 2 veces más rápido en la versión que la depuración sin afirmaciones / etc en el bucle principal.
Bengie
Además, si le importa el uso de la memoria, puede haber grandes diferencias. He visto un caso en el que un servicio de Windows multiproceso compilado en modo de depuración utilizaba 700 MB por subproceso, frente a 50 MB por subproceso en la versión de lanzamiento. La compilación de depuración se quedó rápidamente sin memoria en condiciones de uso típicas.
o. nate
@Bengie: ¿verificó que si adjunta un depurador a la versión de lanzamiento, todavía se ejecuta 2 veces más rápido? Tenga en cuenta que la cita anterior dice que la optimización JIT se ve afectada por si el depurador está conectado.
ToolmakerSteve

Respuestas:

99

Parcialmente cierto. En modo de depuración, el compilador emite símbolos de depuración para todas las variables y compila el código tal como está. En el modo de lanzamiento, se incluyen algunas optimizaciones:

  • las variables no utilizadas no se compilan en absoluto
  • el compilador extrae algunas variables del bucle si se demuestra que son invariantes
  • el código escrito bajo la directiva #debug no está incluido, etc.

El resto depende del JIT.

Lista completa de optimizaciones aquí cortesía de Eric Lippert .

Adrian Zanescu
fuente
10
Y no te olvides de Debug.Asserts! En DEBUG build, si fallan, detendrán el hilo y abrirán un cuadro de mensaje. En el lanzamiento no se compilan en absoluto. Esto se aplica a todos los métodos que tienen [ConditionalAttribute].
Ivan Zlatanov
13
El compilador de C # no realiza optimizaciones de llamadas de cola; la inquietud lo hace. Si desea una lista precisa de lo que hace el compilador de C # cuando el interruptor de optimización está activado
Eric Lippert
63

No hay ningún artículo que "pruebe" nada sobre una pregunta de rendimiento. La forma de demostrar una afirmación sobre el impacto en el rendimiento de un cambio es probarlo en ambos sentidos y probarlo en condiciones realistas pero controladas.

Estás haciendo una pregunta sobre el rendimiento, así que claramente te importa el rendimiento. Si le importa el rendimiento, lo correcto es establecer algunos objetivos de rendimiento y luego redactarse un conjunto de pruebas que rastree su progreso en relación con esos objetivos. Una vez que tenga un conjunto de pruebas de este tipo, puede usarlo fácilmente para comprobar por sí mismo la verdad o la falsedad de declaraciones como "la construcción de depuración es más lenta".

Y, además, podrá obtener resultados significativos. "Más lento" no tiene sentido porque no está claro si es un microsegundo más lento o veinte minutos más lento. "10% más lento en condiciones realistas" es más significativo.

Dedique el tiempo que habría dedicado a investigar esta pregunta en línea para construir un dispositivo que responda la pregunta. Obtendrá resultados mucho más precisos de esa manera. Todo lo que lea en línea es solo una suposición sobre lo que podría suceder. Razón de los hechos que recopiló usted mismo, no de las conjeturas de otras personas sobre cómo podría comportarse su programa.

Eric Lippert
fuente
2
Creo que puede preocuparse por el rendimiento y aún así tener el deseo de usar "depuración". Por ejemplo, si la mayor parte de su tiempo está esperando dependencias, no creo que construir en modo de depuración haga una gran diferencia, sin embargo, tiene el beneficio adicional de obtener números de línea en los seguimientos de la pila, lo que puede ayudar a corregir errores más rápido y hacer usuarios más felices El punto es que debe sopesar los pros y los contras, y una declaración general de "ejecución de depuración es más lenta, pero solo si está vinculado a la CPU" es suficiente para ayudar con la decisión.
Josh Mouch
11

No puedo comentar sobre el rendimiento, pero el consejo "no implemente la depuración en producción" todavía se mantiene simplemente porque el código de depuración generalmente hace bastantes cosas de manera diferente en productos grandes. Por un lado, es posible que tenga interruptores de depuración activos y por otro probablemente habrá comprobaciones de sanidad redundantes adicionales y salidas de depuración que no pertenecen al código de producción.

Konrad Rudolph
fuente
Estoy de acuerdo con usted en ese tema, pero esto no responde a la pregunta principal
sagie
55
@sagie: sí, soy consciente de eso, pero pensé que valía la pena aclararlo.
Konrad Rudolph
6

Desde msdn social

No está bien documentado, esto es lo que sé. El compilador emite una instancia de System.Diagnostics.DebuggableAttribute. En la versión de depuración, la propiedad IsJitOptimizerEnabled es True, en la versión de lanzamiento es False. Puede ver este atributo en el manifiesto de ensamblado con ildasm.exe

El compilador JIT usa este atributo para deshabilitar optimizaciones que dificultarían la depuración. Los que mueven el código como el izado invariante de bucle. En casos seleccionados, esto puede hacer una gran diferencia en el rendimiento. Aunque generalmente no.

Asignar puntos de interrupción a direcciones de ejecución es el trabajo del depurador. Utiliza el archivo .pdb y la información generada por el compilador JIT que proporciona la instrucción IL para codificar la asignación de direcciones. Si escribiera su propio depurador, usaría ICorDebugCode :: GetILToNativeMapping ().

Básicamente, la implementación de depuración será más lenta ya que las optimizaciones del compilador JIT están deshabilitadas.

Neil
fuente
3

Lo que lees es bastante válido. La versión suele ser más sencilla debido a la optimización JIT, sin incluir el código de depuración (#IF DEBUG o [Condicional ("DEBUG")]), la carga mínima del símbolo de depuración y, a menudo, no se considera un ensamblaje más pequeño que reducirá el tiempo de carga. El rendimiento diferente es más obvio cuando se ejecuta el código en VS debido a los PDB más extensos y los símbolos que se cargan, pero si lo ejecuta de forma independiente, las diferencias de rendimiento pueden ser menos evidentes. Cierto código se optimizará mejor que otro y está utilizando la misma heurística de optimización como en otros idiomas.

Scott tiene una buena explicación sobre la optimización del método en línea aquí

Consulte este artículo que brinda una breve explicación de por qué es diferente en el entorno ASP.NET para la configuración de depuración y lanzamiento.

Fadrian Sudaman
fuente
3

Una cosa que debe tener en cuenta, con respecto al rendimiento y si el depurador está conectado o no, algo que nos tomó por sorpresa.

Teníamos un código, que involucraba muchos bucles estrechos, que parecía tardar una eternidad en depurar, pero que funcionaba bastante bien por sí solo. En otras palabras, ningún cliente o clientes experimentaron problemas, pero cuando estábamos depurando parecía funcionar como la melaza.

El culpable fue Debug.WriteLineuno de los lazos estrechos, que escupió miles de mensajes de registro, salidos de una sesión de depuración hace un tiempo. Parece que cuando el depurador está conectado y escucha dicha salida, hay una sobrecarga involucrada que ralentiza el programa. Para este código en particular, estaba en el orden de tiempo de ejecución de 0.2-0.3 segundos por sí solo, y más de 30 segundos cuando se adjuntó el depurador.

Sin embargo, la solución simple es eliminar los mensajes de depuración que ya no se necesitaban.

Lasse V. Karlsen
fuente
2

En el sitio msdn ...

Configuraciones de lanzamiento versus depuración

Mientras todavía está trabajando en su proyecto, normalmente creará su aplicación utilizando la configuración de depuración, porque esta configuración le permite ver el valor de las variables y controlar la ejecución en el depurador. También puede crear y probar compilaciones en la configuración de lanzamiento para asegurarse de que no haya introducido ningún error que solo se manifieste en un tipo de compilación u otro. En la programación de .NET Framework, estos errores son muy raros, pero pueden ocurrir.

Cuando esté listo para distribuir su aplicación a los usuarios finales, cree una versión de lanzamiento, que será mucho más pequeña y generalmente tendrá un rendimiento mucho mejor que la configuración de depuración correspondiente. Puede establecer la configuración de compilación en el panel de compilación del Diseñador de proyectos o en la barra de herramientas de compilación. Para obtener más información, consulte Configuraciones de compilación.

hallie
fuente
1

En gran medida, eso depende de si su aplicación está vinculada al cómputo, y no siempre es fácil saberlo, como en el ejemplo de Lasse. Si tengo la más mínima pregunta sobre lo que está haciendo, la detengo un par de veces y examino la pila. Si hay algo extra que realmente no necesitaba, eso lo detecta de inmediato.

Mike Dunlavey
fuente
1

Recientemente me encontré con un problema de rendimiento. La lista completa de productos tomaba demasiado tiempo, unos 80 segundos. Ajusté la base de datos, mejoré las consultas y no hubo ninguna diferencia. Decidí crear un TestProject y descubrí que el mismo proceso se ejecutó en 4 segundos. Luego me di cuenta de que el proyecto estaba en modo de depuración y el proyecto de prueba estaba en modo de lanzamiento. Cambié el proyecto principal al modo Release y la lista completa de productos solo tardó 4 segundos en mostrar todos los resultados.

Resumen: el modo de depuración es mucho más lento que el modo de ejecución, ya que mantiene la información de depuración. Siempre debe implementar en modo Relase. Aún puede tener información de depuración si incluye archivos .PDB. De esa manera puede registrar errores con números de línea, por ejemplo.

Francisco Goldenstein
fuente
¿Por "modo de ejecución" quieres decir "Liberar"?
Ron Klein
Sí exactamente. La versión no tiene toda la sobrecarga de depuración.
Francisco Goldenstein
1

Los modos de depuración y liberación tienen diferencias. Hay una herramienta Fuzzlyn : es un fuzzer que utiliza Roslyn para generar programas aleatorios de C #. Ejecuta estos programas en .NET core y garantiza que den los mismos resultados cuando se compilan en modo de depuración y liberación.

Con esta herramienta se encontró y se reportaron muchos errores.

Sergey Ponomarev
fuente