Raj Aththanayake's Blog Raj Aththanayake's Blog | Struct Layouts Performance Tip
Home > C#

Struct Layouts Performance Tip

2. March 2012

Most developers aware of that Structs needed to be in smaller size (16byte or less) so they can run efficiently as possible. If you are interested in how the Struct size contributes to better performance, please refer to this question. This post is about another less popular tip that may contribute to improve the efficiency of Structs.

Just a bit of back ground on Layouts:

The way you structure your code, for example the order you specify fields within a type, is not necessarily the same way the CLR organize those fields. For performance reasons, CLR can re-arrange those fields of a type any way it chooses. Using StructureLayoutAttribute attribute, you can explicitly tell CLR the way you want to organize your fields. If you don’t specify a StructureLayoutAttribute, the compiler selects the most appropriate layout it thinks best.

For Structs, C# compiler creates the LayoutType.Sequnetial by default. This means the fields should stay in the order defined by the programmer.

(Note: For Reference types C# compiler selects the LayoutType.Auto by default.)

Below is a C# Struct with no explicit layout and the corresponding generated IL.

image

The Structs are commonly used when interoperating with unmanaged code. Therefore the fields must stay in the order that programmer define for this to work. But most user defined value types/Structs you create have nothing to do with interoperability with unmanaged code. Therefore if you specify the LayoutKind.Auto, the runtime automatically decide the appropriate layout.

clip_image004

If you do a quick benchmark on both layouts you see the LayoutKind.Auto is much faster than the LayoutKind.Sequential.

clip_image006

Result–

(Time in milliseconds)

clip_image007

(Config: .NET 4, x86, and Release build)

If you want to look at the sample code is below.

 

 

   1: //uses LayoutKind.Sequence by default
   2:     public struct StructSeq
   3:     {
   4:         private readonly Byte mb;
   5:         private readonly Int16 mx;
   6:         public string a;
   7:         public string b;
   8:         public string c;
   9:         public string d;
  10:     }
  11:  
  12:     [StructLayout(LayoutKind.Auto)]
  13:     public struct StructAuto
  14:     {
  15:         private readonly Byte mb;
  16:         private readonly Int16 mx;
  17:         public string a;
  18:         public string b;
  19:         public string c;
  20:         public string d;
  21:     }
  22:  
  23:     public sealed class Program
  24:     {
  25:         public static void Main()
  26:         {
  27:             StructSeq sq = new StructSeq();
  28:             Stopwatch sw1 = new Stopwatch();
  29:             sw1.Start();
  30:             for (int i = 0; i < 8000000; i++)
  31:             {
  32:                 ProcessStructSeq(ref sq);
  33:             }
  34:             sw1.Stop();
  35:             Console.WriteLine("Struct LayoutKind.Sequence (default) {0}", sw1.Elapsed.TotalMilliseconds);
  36:  
  37:             StructAuto so = new StructAuto();
  38:             Stopwatch sw2 = new Stopwatch();
  39:             sw2.Start();
  40:             for (int i = 0; i < 8000000; i++)
  41:             {
  42:                 ProcessStructAuto(ref so);
  43:             }
  44:             sw2.Stop();
  45:             Console.WriteLine("Struct LayoutKind.Auto (explicit) {0}", sw2.Elapsed.TotalMilliseconds);          
  46:  
  47:             Console.ReadLine();
  48:         }
  49:  
  50:         public static void ProcessStructSeq(ref StructSeq structSeq)
  51:         {
  52:             structSeq.a = "1";
  53:             structSeq.b = "2";
  54:             structSeq.c = "3";
  55:             structSeq.d = "4";            
  56:         }
  57:  
  58:         public static void ProcessStructAuto(ref StructAuto structAuto)
  59:         {
  60:             structAuto.a = "1";
  61:             structAuto.b = "2";
  62:             structAuto.c = "3";
  63:             structAuto.d = "4";            
  64:         }
  65:     }

C#

Comments are closed