VB.NET Vs C# speed mythbuster

“A release build C# assembly is faster as a VB.Net assembly”  ( SIGH )

How can we bust this myth and explain the differences that people seem to have experienced ? , well there are some reassons why this is occuring and i would like to share them with you .

A debug build C# assembly is faster

VB.Net inserts more nop instructions in a debug build IL image this is the reasson why the VB IDE has verry advanced debug features in the Visual studio IDE and C#  not ( or at least not so advanced as the VB.Net IDE )

.method public static void  Main() cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size       14 (0xe)
.maxstack  8
IL_0000:  nop
IL_0001:  ldstr   “Hello World”
IL_0006:  call    void [mscorlib]System.Console::WriteLine(string)
IL_000b:  nop
IL_000c:  nop
IL_000d:  ret
} // end of method Module1::Main

 The VB.Net Compiler  generates standard overflow checks for integer operations

Benchmarks results have been posted that do not accurately compare the performance of Visual Basic .NET to other languages , so switch the compiler option to the same default setting as the C# compiler is using and that is no checking at all , or write in C# yourself a checking struct

          VB.Net

Public Shared Sub RunLoop()
Dim I As Integer
Dim max As Integer = 500000000
Dim sum As Integer = 0

For I = 1 To max
sum += 1
Next

End Sub

              results in

.method public static void  RunLoop() cil managed
{
// Code size       27 (0x1b)
.maxstack  2
.locals init ([0] int32 I,
[1] int32 max,
[2] int32 sum,
[3] int32 _Vb_t_i4_0)
IL_0000:  ldc.i4     0x1dcd6500
IL_0005:  stloc.1
IL_0006:  ldc.i4.0
IL_0007:  stloc.2
IL_0008:  ldc.i4.1
IL_0009:  ldloc.1
IL_000a:  stloc.3
IL_000b:  stloc.0
IL_000c:  br.s       IL_0016
IL_000e:  ldloc.2
IL_000f:  ldc.i4.1
IL_0010:  add
IL_0011:  stloc.2
IL_0012:  ldloc.0
IL_0013:  ldc.i4.1
IL_0014:  add
IL_0015:  stloc.0
IL_0016:  ldloc.0
IL_0017:  ldloc.3
IL_0018:  ble.s      IL_000e
IL_001a:  ret
} // end of method Class1::RunLoop

            C#

public static void RunLoop()
{
int i;
int max = 500000000;
int sum = 0;
int loopLimit = max;
for (i = 1; i <= loopLimit; i++)
{
sum += 1;
}
}

          results in

.method private hidebysig static void  RunLoop() cil managed
{
// Code size       27 (0x1b)
.maxstack  2
.locals init ([0] int32 i,
[1] int32 max,
[2] int32 sum,
[3] int32 loopLimit)
IL_0000:  ldc.i4     0x1dcd6500
IL_0005:  stloc.1
IL_0006:  ldc.i4.0
IL_0007:  stloc.2
IL_0008:  ldloc.1
IL_0009:  stloc.3
IL_000a:  ldc.i4.1
IL_000b:  stloc.0
IL_000c:  br.s       IL_0016
IL_000e:  ldloc.2
IL_000f:  ldc.i4.1
IL_0010:  add
IL_0011:  stloc.2
IL_0012:  ldloc.0
IL_0013:  ldc.i4.1
IL_0014:  add
IL_0015:  stloc.0
IL_0016:  ldloc.0
IL_0017:  ldloc.3
IL_0018:  ble.s      IL_000e
IL_001a:  ret
} // end of method Class1::RunLoop

The only difference is the order of the instructions on lines IL_0008, IL_0009, and IL_000a

The Visual Basic .NET compiler will generate the IL instruction add.ovf for these addition operations. The add.ovf instruction includes an overflow check and throws an exception if the sum exceeds the capacity of the target data type  , the add.ovf instruction results in safer code however a Visual Basic coder could choose to dissable the overflow check at the compiler options tab , however standard it is turned on for a debug and a release build.

If we run the code i showed above there is no noticable speed difference although VB.Net actually has one extra integer on the stack however this is not measurable .

Unique Visual Basic Constructs

The Visual Basic language constructs are wrappers for methods and properties from the divers system classes and do not introduce significant performance penalties however in a comparisation , one should mimic the behavior of these shortcut constructs or use in both languages the same framework classes  .

      For instance

The VB language method Callbyname is not a one on one equivalant to objectPointer.GetType().GetProperty(“NameOfProperty”).SetValue(objectPointer, “value”, null) as some people seem to think , as Callbyname results in a few hundred  lines of  IL code where depending on the type of called object different checks and invocation paths are chosen  . So a C# coder should actually also write his code as defensive as the VB library does or in a comparisation the same framework methods should be used !

Conclusion

A release builded and equal style written .Net application is just as fast executing wether it was written in C# or VB.Net

Advertisements