2011-08-16 14 views
9

I'm trying to build a code sample para mostrar la optimización del código por el compilador al multiplicar con una potencia de 2 números. Sin embargo, cuando enciendo el código de Optimize en el IL permanece principalmente igual. ¿Alguna idea de lo que estoy haciendo mal aquí?¿Cuándo el compilador optimiza mi código

El código:

int nr; 
int result; 
var stopwatch = new Stopwatch(); 

nr = 5; 

stopwatch.Start(); 
    result = nr * 4; 
stopwatch.Stop(); 

Console.WriteLine(result); 
Console.WriteLine(stopwatch.Elapsed.ToString() + "ms ellapsed"); 
stopwatch.Reset(); 

stopwatch.Start(); 
result = nr << 2; 
stopwatch.Stop(); 

Console.WriteLine(result); 
Console.WriteLine(stopwatch.Elapsed.ToString() + "ms ellapsed"); 

no optimizado IL:

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  130 (0x82) 
    .maxstack 2 
    .locals init ([0] int32 nr, 
      [1] int32 result, 
      [2] class [System]System.Diagnostics.Stopwatch stopwatch, 
      [3] valuetype [mscorlib]System.TimeSpan CS$0$0000, 
      [4] valuetype [mscorlib]System.TimeSpan CS$0$0001) 
    IL_0000: newobj  instance void [System]System.Diagnostics.Stopwatch::.ctor() 
    IL_0005: stloc.2 
    IL_0006: ldc.i4.5 
    IL_0007: stloc.0 
    IL_0008: ldloc.2 
    IL_0009: callvirt instance void [System]System.Diagnostics.Stopwatch::Start() 
    IL_000e: ldloc.0 
    IL_000f: ldc.i4.4 
    IL_0010: mul 
    IL_0011: stloc.1 
    IL_0012: ldloc.2 
    IL_0013: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop() 
    IL_0018: ldloc.1 
    IL_0019: call  void [mscorlib]System.Console::WriteLine(int32) 
    IL_001e: ldloc.2 
    IL_001f: callvirt instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed() 
    IL_0024: stloc.3 
    IL_0025: ldloca.s CS$0$0000 
    IL_0027: constrained. [mscorlib]System.TimeSpan 
    IL_002d: callvirt instance string [mscorlib]System.Object::ToString() 
    IL_0032: ldstr  "ms ellapsed" 
    IL_0037: call  string [mscorlib]System.String::Concat(string, 
                   string) 
    IL_003c: call  void [mscorlib]System.Console::WriteLine(string) 
    IL_0041: ldloc.2 
    IL_0042: callvirt instance void [System]System.Diagnostics.Stopwatch::Reset() 
    IL_0047: ldloc.2 
    IL_0048: callvirt instance void [System]System.Diagnostics.Stopwatch::Start() 
    IL_004d: ldloc.0 
    IL_004e: ldc.i4.2 
    IL_004f: shl 
    IL_0050: stloc.1 
    IL_0051: ldloc.2 
    IL_0052: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop() 
    IL_0057: ldloc.1 
    IL_0058: call  void [mscorlib]System.Console::WriteLine(int32) 
    IL_005d: ldloc.2 
    IL_005e: callvirt instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed() 
    IL_0063: stloc.s CS$0$0001 
    IL_0065: ldloca.s CS$0$0001 
    IL_0067: constrained. [mscorlib]System.TimeSpan 
    IL_006d: callvirt instance string [mscorlib]System.Object::ToString() 
    IL_0072: ldstr  "ms ellapsed" 
    IL_0077: call  string [mscorlib]System.String::Concat(string, 
                   string) 
    IL_007c: call  void [mscorlib]System.Console::WriteLine(string) 
    IL_0081: ret 
} // end of method Program::Main 

IL optimizada:

.method private hidebysig static void Main(string[] args) cil managed 
{ 
    .entrypoint 
    // Code size  130 (0x82) 
    .maxstack 2 
    .locals init ([0] int32 nr, 
      [1] int32 result, 
      [2] class [System]System.Diagnostics.Stopwatch stopwatch, 
      [3] valuetype [mscorlib]System.TimeSpan CS$0$0000, 
      [4] valuetype [mscorlib]System.TimeSpan CS$0$0001) 
    IL_0000: newobj  instance void [System]System.Diagnostics.Stopwatch::.ctor() 
    IL_0005: stloc.2 
    IL_0006: ldc.i4.5 
    IL_0007: stloc.0 
    IL_0008: ldloc.2 
    IL_0009: callvirt instance void [System]System.Diagnostics.Stopwatch::Start() 
    IL_000e: ldloc.0 
    IL_000f: ldc.i4.4 
    IL_0010: mul 
    IL_0011: stloc.1 
    IL_0012: ldloc.2 
    IL_0013: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop() 
    IL_0018: ldloc.1 
    IL_0019: call  void [mscorlib]System.Console::WriteLine(int32) 
    IL_001e: ldloc.2 
    IL_001f: callvirt instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed() 
    IL_0024: stloc.3 
    IL_0025: ldloca.s CS$0$0000 
    IL_0027: constrained. [mscorlib]System.TimeSpan 
    IL_002d: callvirt instance string [mscorlib]System.Object::ToString() 
    IL_0032: ldstr  "ms ellapsed" 
    IL_0037: call  string [mscorlib]System.String::Concat(string, 
                   string) 
    IL_003c: call  void [mscorlib]System.Console::WriteLine(string) 
    IL_0041: ldloc.2 
    IL_0042: callvirt instance void [System]System.Diagnostics.Stopwatch::Reset() 
    IL_0047: ldloc.2 
    IL_0048: callvirt instance void [System]System.Diagnostics.Stopwatch::Start() 
    IL_004d: ldloc.0 
    IL_004e: ldc.i4.2 
    IL_004f: shl 
    IL_0050: stloc.1 
    IL_0051: ldloc.2 
    IL_0052: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop() 
    IL_0057: ldloc.1 
    IL_0058: call  void [mscorlib]System.Console::WriteLine(int32) 
    IL_005d: ldloc.2 
    IL_005e: callvirt instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed() 
    IL_0063: stloc.s CS$0$0001 
    IL_0065: ldloca.s CS$0$0001 
    IL_0067: constrained. [mscorlib]System.TimeSpan 
    IL_006d: callvirt instance string [mscorlib]System.Object::ToString() 
    IL_0072: ldstr  "ms ellapsed" 
    IL_0077: call  string [mscorlib]System.String::Concat(string, 
                   string) 
    IL_007c: call  void [mscorlib]System.Console::WriteLine(string) 
    IL_0081: ret 
} // end of method Program::Main 

pensé que el compilador optimizar la declaración mul a una declaración SHL?
Mi conocimiento de IL es muy limitado (si no inexistente).

+2

Si el 'mul' se optimiza en un' shl', y no tengo ni idea de si lo hace o no, casi con seguridad se hará cuando el IL se ajuste al código específico de la plataforma. – LukeH

Respuesta

7

Este es el código generado por la fluctuación en la versión de lanzamiento:

0000003e mov   ecx,14h 

El optimizador es demasiado inteligente como para generar código para una multiplicación cuando se conoce los valores de operando. Si reemplaza nr = 5; nr = int.Parse ("5") de modo que la fluctuación no puede conocer los valores de operando entonces se genera el código para la multiplicación:

0000005c lea   ebx,[rdi*4+00000000h] 

que se aprovecha del multiplicador integrado en la lógica de generación de dirección en el CPU, lo que permite que la instrucción se solape con otra instrucción que usa la ALU. Lo que hace que la multiplicación sea esencialmente gratuita. Esa es la salida de la fluctuación de fase de 64 bits, la fluctuación de fase de 32 bits genera esto:

0000004d shl   edi,2 

¿Qué es lo que usted esperaba. Documenté el tipo de optimizaciones realizadas por el jitter en this post.

+0

¡Impresionante, gracias! –

7

El indicador "optimizar" no hace mucho en la fase de compilación C# a IL. Es hace hacer la diferencia, pero no para este tipo de cosas.

Espero que ese tipo de optimización sea manejada por el compilador JIT en su lugar.

+0

¿Hay alguna documentación o algo que describa exactamente qué productos CSC optimiza? – Zenwalker

+0

@zenwalker: no es que yo sepa, es el tipo de cosas que el equipo compilador debería poder cambiar entre versiones como un detalle de implementación. Puede encontrar algunas publicaciones en el blog al respecto ... –

+5

@zenwalker: http://blogs.msdn.com/b/ericlippert/archive/2009/06/11/what-does-the-optimize-switch-do. aspx – LukeH

Cuestiones relacionadas