Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# to CIL Boxing vs. ToString Cost

I'm reading the book CLR via C# (4th edition), not as a newcomer to C# but as someone who knows the language trying to improve my grasp on the underlying functionality of the CLR.

Anyway, in this book an example is given (pg127-131) when discussing boxing/unboxing of value types which ends with a call to Console.WriteLine with a value type being concatenated to a string being passed as the argument.

The book explains that boxing and unboxing/copy operations cause overhead, which I already knew, but it then stated that the example could be optimized by running .ToString() on the value type being passed in.

I created an example program and compiled it, then used ILDASM to inspect the IL it generated. The version with ToString essentially is identical, but replaces the "box" instruction with a "call" to ToString (no shock there).

I benchmarked the code in a loop of 100000 runs, and there was no difference (it fluctuated which one was faster). I realize that other factors come into play when benchmarking (caches, etc.), but by the way the book explained it I had expected to see a significant difference when avoiding the "box" instruction even in a naieve benchmark..

Is it just that calling a function isn't much better? Is there a boxing operation going on in the ToString that nullifies the benefits and the book is wrong? Can someone shed some light on this?

For reference, here are the two ILDASM readouts:


.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       24 (0x18)
  .maxstack  2
  .locals init (int32 V_0)
  IL_0000:  ldc.i4.4
  IL_0001:  stloc.0
  IL_0002:  ldloc.0
  IL_0003:  box        [mscorlib]System.Int32
  IL_0008:  ldstr      "."
  IL_000d:  call       string [mscorlib]System.String::Concat(object,
                                                              object)
  IL_0012:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0017:  ret
} // end of method Program::Main

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       25 (0x19)
  .maxstack  2
  .locals init (int32 V_0)
  IL_0000:  ldc.i4.4
  IL_0001:  stloc.0
  IL_0002:  ldloca.s   V_0
  IL_0004:  call       instance string [mscorlib]System.Int32::ToString()
  IL_0009:  ldstr      "."
  IL_000e:  call       string [mscorlib]System.String::Concat(string,
                                                              string)
  IL_0013:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_0018:  ret
} // end of method Program::Main
like image 673
Yushatak Avatar asked Mar 11 '15 19:03

Yushatak


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is the full name of C?

In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr. Stroustroupe.

Is C language easy?

C is a general-purpose language that most programmers learn before moving on to more complex languages. From Unix and Windows to Tic Tac Toe and Photoshop, several of the most commonly used applications today have been built on C. It is easy to learn because: A simple syntax with only 32 keywords.

Why do we write C?

We write C for Carbon Because in some element the symbol of the element is taken form its first words and Co for Cobalt beacause in some elements the symbol of the element is taken from its first second letters, so that the we don't get confuse.


1 Answers

The CLR is likely inlining the call to string.Concat(object,object) which results in the same code as your "optimized" version. Note that the C# compiler will leave a lot of these kinds of optimizations up to the CLR, since it has better tools available to do them.

Other than a couple null checks (which would be optimized out) it simply calls string.Concat(left.ToString(),right.ToString()) which would be simplified to string.Concat(left,right.ToString()) since the CLR would see that ToString() just returns this.

Thus the executing code is likely identical in both cases.

like image 144
Guvante Avatar answered Sep 21 '22 17:09

Guvante