Speed question... constant vs others

I need to specify colors in many places for graphics…was wondering which of these would be the fastest running…maybe they are all the same


const Color abcd = Skewworks.NETClix.Colors.Red;
 static Color wxyz = Skewworks.NETClix.Colors.Red;
or just use Skewworks.NETClix.Colors.Red everywhere

Ildasm is a great tool to check how generated IL code looks like in both cases. This will give you the answer for sure.

@ Hoyt - const values are compiled directly into the IL, therefore at runtime the value is used directly, so ultimately this is the same as using the value everywhere. In the case of the static, even if it is read only, there is an extra level of indirection, the value will be read from the memory location of the variable.

Given the above, using the comst variable or the value directly will be faster due to the fact that that there will be fewer memory accesses required to load the varlue onto the Execution stack. Of course the proof is in the pudding, but personally I would blindly go with the cost declaration unless I have some specific versioning requirement , but this is another issue any I cannot think of a scenario that this would actually apply on an embedded device.

1 Like

so Skewworks.NETClix.Colors.Red is compiled just as a constant would be?

Doubt it. I’m betting Red is an enum value which is not the same as a constant.

@ ianlee74 - enum contains const values.

It either is a const (enum) value or an instance declared as static readonly.

2 Likes

Sorry for taking so long to get to this, I typed my initial reply before leaving for work this morning and only just got back to the PC. Let me try provide a little more detail.

As long as the expression assigned in the const declaration can be evaluated at compile time, which is the only legal declaration of a const in C#, the compiler will evaluate the expression and replace all references to the const with the actual value of the evaluated expression.

For example (This is just hand coded so excuse any typos, read it for what it is, an example to demonstrate the concept)


// Declare some constants
const int MillisecondsPerSecond = 1000;
const int MillisecondsPerMinute = 60 * MillisecondsPerSecond;

...

// Now use one of the constants, assume that  totalMilliseconds is a value that came from some timing operation

var totalMinutes = totalMilliseconds / MillisecondsPerMinute;

When the above is compiled the compiler actually evaluates the expression 60 * MillisecondsPerSecond and gets the value 60000, the compiler can do this because the entire expression is made up of constants that cannot change at runtime therefore the compile time evaluation is safe. The compiler then replaces all references to MillisecondsPerMinute with the literal value 60000. So the above compiles as if you have typed the following:


var totalMinutes = totalMilliseconds / 60000;

From this you can see that using the constant or the literal value does not have any performance difference.

There is a serious consequence to this. If you are building a library and you define a const as Public, users of you library will use your that const which in their code will be replaced at compile time with the value of the const at the time you compiled the library. So it is as if the caller had just directly typed the resulting value into their own code.

Now at a later point, you release a new version of your library in which the value of the const has changed, external will not see the changed value it they just update your library assemblies without recompiling their code which references the const value within your library. This is because the const value was baked into their binary files at the time their compilation took place with the older version of the library.

So the golden rule, make sure that what you think is const today is truly constant. Otherwise you should consider using read only variable, which have the overhead of an additional level of indirection, but that might bring the required flexibility.

Few, sorry for the long post. I hope I have been able to help in some way.

This was discussed in a thread several months back and I remember someone (Errol?) posting the IL code that proved that enum values are not treated as constants in .NET. I can’t find that thread now, though… The problem as I remember it was that enums are objects and so the IL has to create an instance of it before it can use the value. This object instantiation is not necessary when just using a const value.

@ ianlee74 - Enums are value types with const field members in the IL below you will see this as ‘static literal’, because the fields are static there is no need to create an instance of the enum type.

Here is a quick test that can be used to validate this.

Given the following C# program (I targeted .NET MF just in case, it made a difference)


namespace MFConstTest
{
  public class Program
  {
    enum MyEnum 
    {
      Value1 = 100,
      Value2 = 200,
      Value3 = 300
    }

    private const MyEnum _theEnum = MyEnum.Value2;

    public static void Main()
    {
      Debug.Print("The enum value" + _theEnum.ToString());
    }

  }
}

The resulting IL, trimmed for readability


.class public auto ansi beforefieldinit MFConstTest.Program
       extends [mscorlib]System.Object
{
  .class auto ansi sealed nested private MyEnum
         extends [mscorlib]System.Enum
  {
    .field public specialname rtspecialname int32 value__
    .field public static literal valuetype MFConstTest.Program/MyEnum Value1 = int32(0x00000064)
    .field public static literal valuetype MFConstTest.Program/MyEnum Value2 = int32(0x000000C8)
    .field public static literal valuetype MFConstTest.Program/MyEnum Value3 = int32(0x0000012C)
  } // end of class MyEnum

  .field private static literal valuetype MFConstTest.Program/MyEnum _theEnum = int32(0x000000C8)
  .method public hidebysig static void  Main() cil managed
  {
    .entrypoint
    // Code size       33 (0x21)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldstr      "The enum value"
    IL_0006:  ldc.i4     0xc8
    IL_000b:  box        MFConstTest.Program/MyEnum
    IL_0010:  callvirt   instance string [mscorlib]System.Object::ToString()
    IL_0015:  call       string [mscorlib]System.String::Concat(string,
                                                                string)
    IL_001a:  call       void [Microsoft.SPOT.Native]Microsoft.SPOT.Debug::Print(string)
    IL_001f:  nop
    IL_0020:  ret
  } // end of method Program::Main
} // end of class MFConstTest.Program

Notice the following two lines


    IL_0006:  ldc.i4     0xc8 --------------------------------------------> Here is the literal value from the  _theEnum being loaded onto the stack
    IL_000b:  box        MFConstTest.Program/MyEnum -------> Here it is boxed so that the ToString method can be called, boxing proves that it is a value type

If we remove the const and just make the field static then the above changes to


    IL_0006:  ldsfld     valuetype MFConstTest.Program/MyEnum MFConstTest.Program::_theEnum
    IL_000b:  box        MFConstTest.Program/MyEnum

Now the static field member is accessed and the value loaded onto the stack with ‘ldsfld’ opcode.

That was me, and the post is here: http://www.tinyclr.com/forum/topic?id=6141&page=18#msg60357

What I said was that both enums and consts are treated exactly the same (as consts), but that the enum resulted in more IL code. Performance is the same, compiled binary size is not the same.