September 17, 2009

Static field access performance

I'm working on Tuples performance now. Few days ago Alexey Kochetov faced an issue with performance I'd like to describe here. The answer is almost obvious when you know how .NET deals with generics; otherwise this scenario appears a bit strange.

So what do you think... Is static field access operation provides constant performance?

Take a look at this code (open my original post to see syntax highlighting):
public class Host
{
  public static object StaticField;

  public virtual void GetStaticField(int iterationCount)
  {
    object o = null;
    for (int i = 0; i<iterationCount; i++)
      o = StaticField;
  }
}

public class Host<T> : Host
{
  // We're using different StaticField here
  public new static object StaticField;

  public override void GetStaticField(int iterationCount)
  {
    object o = null;
    for (int i = 0; i<iterationCount; i++)
      o = StaticField;
  }
}

Performance test for it:
int count = 1000000000;

Host host = new Host();
using (new Measurement("Static field of Host", MeasurementOptions.Log, count))
  host.GetStaticField(count);

host = new Host<int>();
using (new Measurement("Static field of Host<int>", MeasurementOptions.Log, count))
  host.GetStaticField(count);

host = new Host<Array>();
using (new Measurement("Static field of Host<Array>", MeasurementOptions.Log, count))
  host.GetStaticField(count);

Measurement class is IDisposable allowing to measure elapsed time and memory consumption between the moments it was created and disposed. Internally it relies on Stopwatch and GC.* methods.

Test output:
Measurement: Static field of Host:        Operations: 2,599   Billions/second.
Measurement: Static field of Host<int>:   Operations: 2,604   Billions/second.
Measurement: Static field of Host<Array>: Operations: 121,179 Millions/second.

Can you explain this?

If you'd like to see the answer right now, it is here.