I\'m writing a high-performance component with a lot of int-double-int conversions, so I need to know the execution time between them.
static double ToDouble(int
You should use StopWatch.Start and Stop then Elapsed!
const int TIMES = 100_000_000;
var chrono = new Stopwatch();
int val = 0;
chrono.Start();
for ( int i = 1; i <= TIMES; i++ )
val = ToInt(ToDouble(i));
chrono.Stop();
Console.WriteLine(val);
Console.WriteLine(chrono.ElapsedMilliseconds.ToString());
chrono.Restart();
for ( int i = 1; i <= TIMES; i++ )
{
var v1 = (double)i;
val = (int)v1;
}
chrono.Stop();
Console.WriteLine(val);
Console.WriteLine(chrono.ElapsedMilliseconds.ToString());
chrono.Restart();
for ( int i = 1; i <= TIMES; i++ )
val = i;
chrono.Stop();
Console.WriteLine(val);
Console.WriteLine(chrono.ElapsedMilliseconds.ToString());
chrono.Restart();
for ( int i = 1; i <= TIMES; i++ )
;
chrono.Stop();
Console.WriteLine(chrono.ElapsedMilliseconds.ToString());
Output with Debug mode:
729
270
194
218
Using Release build optimized:
84
61
57
31
The first loop in Debug IL:
// value = ToInt(ToDouble(i));
IL_0015: ldloc.2
IL_0016: call float64 ConsoleApp.Program::ToDouble(int32)
IL_001b: call int32 ConsoleApp.Program::ToInt(float64)
IL_0020: stloc.1
The first loop in Release IL:
// value = ToInt(ToDouble(i));
IL_0012: ldloc.2
IL_0013: call float64 ConsoleApp.Program::ToDouble(int32)
IL_0018: call int32 ConsoleApp.Program::ToInt(float64)
IL_001d: stloc.1
The second loop Debug:
// double num = j;
IL_0065: ldloc.s 5
IL_0067: conv.r8
IL_0068: stloc.s 6
// value = (int)num;
IL_006a: ldloc.s 6
IL_006c: conv.i4
IL_006d: stloc.1
The second loop Release:
// value = (int)(double)j;
IL_0054: ldloc.s 4
IL_0056: conv.r8
IL_0057: conv.i4
IL_0058: stloc.1
Proc calls eat a lot of CPU ticks and this is the first thing to consider when optimizing, with loops and calculation.
The compiler optimization is mainly with the loop itself:
// for (int i = 1; i <= 100000000; i++)
IL_0010: ldc.i4.1
IL_0011: stloc.2
// (no C# code)
IL_0012: br.s IL_0026
// loop start (head: IL_0026)
//...
// for (int i = 1; i <= 100000000; i++)
IL_0022: ldloc.2
IL_0023: ldc.i4.1
IL_0024: add
IL_0025: stloc.2
// for (int i = 1; i <= 100000000; i++)
IL_0026: ldloc.2
IL_0027: ldc.i4 100000000
IL_002c: cgt
// (no C# code)
IL_002e: ldc.i4.0
IL_002f: ceq
IL_0031: stloc.3
IL_0032: ldloc.3
IL_0033: brtrue.s IL_0014
// end loop
// for (int i = 1; i <= 100000000; i++)
IL_000c: ldc.i4.1
IL_000d: stloc.1
// (no C# code)
IL_000e: br.s IL_0020
// loop start (head: IL_0020)
// ...
// for (int i = 1; i <= 100000000; i++)
IL_001c: ldloc.1
IL_001d: ldc.i4.1
IL_001e: add
IL_001f: stloc.1
// for (int i = 1; i <= 100000000; i++)
IL_0020: ldloc.1
IL_0021: ldc.i4 100000000
IL_0026: ble.s IL_0010
// end loop
The loops in debug without the console.writeline(val):
// value = ToInt(ToDouble(i));
IL_0015: ldloc.2
IL_0016: call float64 ConsoleApp.Program::ToDouble(int32)
IL_001b: call int32 ConsoleApp.Program::ToInt(float64)
IL_0020: stloc.1
// double num = j;
IL_0065: ldloc.s 5
IL_0067: conv.r8
IL_0068: stloc.s 6
// value = (int)num;
IL_006a: ldloc.s 6
IL_006c: conv.i4
IL_006d: stloc.1
// value = k;
IL_00b7: ldloc.s 8
IL_00b9: stloc.1
// nothing
The loops in release without the console.writeline(val):
// ToInt(ToDouble(i));
IL_0010: ldloc.1
IL_0011: call float64 ConsoleApp.Program::ToDouble(int32)
IL_0016: call int32 ConsoleApp.Program::ToInt(float64)
IL_001b: pop
// _ = (double)j;
IL_004b: ldloc.3
IL_004c: conv.r8
IL_004d: pop
// nothing
// nothing