2010-05-19 17 views
22

Después de actualizar mis proyectos a .NET 4.0 (con VS2010) me di cuenta de que se ejecutan más despacio que en .NET 2.0 (VS2008). Así que decidí referencia una aplicación de consola sencilla tanto en VS2008 & VS2010 con varios marcos de destino:¿Son .NET 4.0 Runtime más lentos que .NET 2.0 Runtime?

using System; 
using System.Diagnostics; 
using System.Reflection; 

namespace RuntimePerfTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine(Assembly.GetCallingAssembly().ImageRuntimeVersion); 
      Stopwatch sw = new Stopwatch(); 

      while (true) 
      { 
       sw.Reset(); 
       sw.Start(); 

       for (int i = 0; i < 1000000000; i++) 
       { 

       } 

       TimeSpan elapsed = sw.Elapsed; 
       Console.WriteLine(elapsed); 
      } 
     } 
    } 
} 

He aquí los resultados:

  • VS2008
    • objetivo Framework 2.0: ~ 0,25 segundos
    • Target Framework 3.0: ~ 0.25 segundos
    • Target Framework 3.5: ~ 0.25 seconds
  • VS2010
    • objetivo Framework 2.0: ~ 3,8 segundos
    • Framework Objetivo 3.0: ~ 3,8 segundos
    • Marco Objetivo 3.5: ~ 1,51 segundos
    • marco destino de perfil 3.5 Cliente: ~ 3.8 segundos
    • Target Framework 4.0: ~ 1.01 segundos
    • Target Framework 4.0 Perfil del cliente: ~ 1.01 segundos

Mi primera conclusión es, obviamente, que los programas compilados con VS2008 actuar más rápido que los programas compilados con VS2010.

¿Alguien puede explicar esos cambios de rendimiento entre VS2008 y VS2010? y entre diferentes marcos de objetivos dentro de VS2010?

+6

¿Está ejecutando estos a través del depurador en Visual Studio o ejecuta las aplicaciones en modo de lanzamiento? –

+2

¿Has probado varias carreras para minimizar las influencias externas? Tal como está, los resultados podrían deberse solo a la casualidad. A pesar de que * parece * concluyente, una sola ejecución arrojaría casi * no * significado en esta prueba. –

+0

¿Has intentado ejecutarlo fuera VS? – eflles

Respuesta

27

Creo que lo tengo.

Si está ejecutando en una máquina de 64 bits, asegúrese de que la compilación esté configurada en "Cualquier CPU" en lugar de "x86". Al hacerlo, corrigió el problema en mi máquina.

El valor predeterminado para los proyectos nuevos cambió en VS2010 de "Cualquier CPU" a "x86" - Creo que esto hizo que Editar y Continuar funcionara de manera predeterminada en máquinas de 64 bits (ya que solo admite x86).

Ejecutar un proceso x86 en una máquina de 64 bits es obviamente algo subóptimo.

EDITAR: Según los comentarios de Dustin, ejecutar x86 en lugar de x64 puede tener ventajas de rendimiento en términos de un uso más eficiente de la memoria (referencias más cortas).

también Me correspondió con Dustin sobre este por correo electrónico, e incluyó estas razones:

Fwiw, la plataforma de destino predeterminado no se ha modificado para apoyar ENC. Tuvimos ya enviado ENC roto en x64 para 2 lanzamientos. Entonces, por sí solo, ENC no era realmente una razón de peso para cambiar. Las principales razones que cambiamos (en ningún orden en particular ) fueron:

  • IntelliTrace no es compatible con x64. Por lo tanto, una de las características nuevas más frescas de no funcionará en Windows x64 para Cualquier proyecto de CPU.

  • x64 EXE ejecutan más lento en x64 Windows que x86 EXEs do. Entonces, la idea de x86 depurar, versión x64 significaría que las compilaciones "optimizadas" de en Release serían que en realidad tienen un peor rendimiento.

  • Quejas de los clientes al implementar una aplicación y que no funciona, aunque funcionó en su máquina. Estos fueron a menudo alrededor de P/Invoke, pero hay muchas otras suposiciones que se pueden hacer en una aplicación que se puede romper cuando se ejecuta con diferente bitness.

Las razones anteriores, junto con el hecho de que un Cualquier CPU no trae beneficios (es decir, que no pueden tomar realmente ventaja de la ampliación del espacio de direcciones porque el EXE todavía se puede ejecutar en x 86) fue el motivo por el que se cambió el valor predeterminado .

Rick Byers tiene una excelente publicación sobre este tema here.

+1

¿Podría ser la diferencia el objetivo de la plataforma? csc.exe usa AnyCPU como valor predeterminado, mientras que VS 2010 ha cambiado el valor predeterminado a x86. –

+0

@ 0xA3: ¿No es eso básicamente lo que dice mi respuesta? –

+4

Sí, lo es, pero su respuesta aún no lo decía cuando escribí mi comentario ;-) Desearía que hubiera una actualización instantánea si alguien actualiza su respuesta. –

8

Creo que su punto de referencia es defectuoso. El código IL de VS 2008 y VS 2010 para su programa de ejemplo es idéntico en el modo de lanzamiento (VS 2008 que apunta .NET 2.0 y VS 2010 que apuntan .NET 4.0 con las configuraciones predeterminadas). Por lo tanto no se debe ver una diferencia en los tiempos entre VS 2008 y VS 2010. Ambos compiladores emiten el siguiente código:

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  69 (0x45) 
    .maxstack 2 
    .locals init ([0] class [System]System.Diagnostics.Stopwatch sw, 
      [1] int32 i, 
      [2] valuetype [mscorlib]System.TimeSpan elapsed) 
    IL_0000: call  class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::GetCallingAssembly() 
    IL_0005: callvirt instance string [mscorlib]System.Reflection.Assembly::get_ImageRuntimeVersion() 
    IL_000a: call  void [mscorlib]System.Console::WriteLine(string) 
    IL_000f: newobj  instance void [System]System.Diagnostics.Stopwatch::.ctor() 
    IL_0014: stloc.0 
    IL_0015: ldloc.0 
    IL_0016: callvirt instance void [System]System.Diagnostics.Stopwatch::Reset() 
    IL_001b: ldloc.0 
    IL_001c: callvirt instance void [System]System.Diagnostics.Stopwatch::Start() 
    IL_0021: ldc.i4.0 
    IL_0022: stloc.1 
    IL_0023: br.s  IL_0029 
    IL_0025: ldloc.1 
    IL_0026: ldc.i4.1 
    IL_0027: add 
    IL_0028: stloc.1 
    IL_0029: ldloc.1 
    IL_002a: ldc.i4  0x3b9aca00 
    IL_002f: blt.s  IL_0025 
    IL_0031: ldloc.0 
    IL_0032: callvirt instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed() 
    IL_0037: stloc.2 
    IL_0038: ldloc.2 
    IL_0039: box  [mscorlib]System.TimeSpan 
    IL_003e: call  void [mscorlib]System.Console::WriteLine(object) 
    IL_0043: br.s  IL_0015 
} // end of method Program::Main 

Una cosa que podría ser diferente es la plataforma de destino. VS 2010 usa x86 como objetivo de la plataforma por defecto, mientras que VS 2008 usa AnyCPU. Si está en un sistema de 64 bits, esto dará lugar a que se utilicen diferentes compiladores JIT para las compilaciones VS 2008 vs. VS 2010. Esto podría llevar a resultados diferentes ya que los compiladores JIT se desarrollan por separado.

5

Estoy de acuerdo en que el punto de referencia es defectuoso.

  • Es demasiado corto.
  • Como se señaló anteriormente, es probable que los diferentes JIT para x86/x64 optimicen el ciclo de forma diferente.
  • Realmente solo prueba las variables de pila que probablemente estén JITted para el acceso de registro rápido. Un punto de referencia mundial más real debería al menos mover el acceso al espacio de direcciones.

Es probable que la mayor parte del tiempo adicional lo tome la capa WoW en los casos x86. Sin embargo, las ineficiencias inherentes de un proceso x64 muy probablemente superarían la sobrecarga de la capa WoW en un punto de referencia más largo que realmente toca la memoria. De hecho, si el punto de referencia fuera acceder a la memoria (creando y accediendo a objetos en el montón), vería los beneficios de optimización del puntero de las capas de WoW.

0

Tenemos el mismo problema. Después de convertir el proyecto wpf de .NET 3.5 (VS2008) a .NET 4 (VS2010), la GUI es mucho menos sensible (casi 1 segundo de retraso por cada clic).

Después de un poco de investigación, supusimos que es porque Visual Studio 2010 consume muchos más recursos y todo es más lento cuando eliminamos los defectos de VS2010. Cuando ejecutamos el proyecto incorporado como .exe, se ejecuta rápidamente de nuevo.

Cuestiones relacionadas