//Source: https://codeblog.jonskeet.uk/2011/08/22/optimization-and-generics-part-1-the-new-constraint/ | |
using System; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Linq.Expressions; | |
using System.Reflection; | |
#pragma warning disable 0169 | |
public class SmallClass { int x; } | |
public class LargeClass { long a, b, c, d, e, f, g, h; } | |
public struct SmallStruct { int x; } | |
public struct LargeStruct { long a, b, c, d, e, f, g, h; } | |
#pragma warning restore 0169 | |
public class Benchmark | |
{ | |
static Action[] Tests = | |
{ | |
SmallStructFromExpression, | |
SmallStructWithConstraint, | |
SmallStructWithProvider, | |
LargeStructFromExpression, | |
LargeStructWithConstraint, | |
LargeStructWithProvider, | |
SmallClassFromExpression, | |
SmallClassWithConstraint, | |
SmallClassWithProvider, | |
LargeClassFromExpression, | |
LargeClassWithConstraint, | |
LargeClassWithProvider, | |
}; | |
private static Func<SmallStruct> smallStructConstructor = GetCtor<SmallStruct>(); | |
private static Func<SmallClass> smallClassConstructor = GetCtor<SmallClass>(); | |
private static Func<LargeStruct> largeStructConstructor = GetCtor<LargeStruct>(); | |
private static Func<LargeClass> largeClassConstructor = GetCtor<LargeClass>(); | |
private static Func<T> GetCtor<T>() | |
{ | |
Type type = typeof(T); | |
Expression body = Expression.New(type); | |
return Expression.Lambda<Func<T>>(body).Compile(); | |
} | |
private static void SmallStructWithConstraint() | |
=> MakeInstance<SmallStruct>(); | |
private static void SmallStructWithProvider() | |
=> MakeInstance<SmallStruct>(() => new SmallStruct()); | |
private static void SmallStructFromExpression() | |
=> MakeInstance<SmallStruct>(smallStructConstructor); | |
private static void LargeStructWithConstraint() | |
=> MakeInstance<LargeStruct>(); | |
private static void LargeStructWithProvider() | |
=> MakeInstance<LargeStruct>(() => new LargeStruct()); | |
private static void LargeStructFromExpression() | |
=> MakeInstance<LargeStruct>(largeStructConstructor); | |
private static void SmallClassWithConstraint() | |
=> MakeInstance<SmallClass>(); | |
private static void SmallClassWithProvider() | |
=> MakeInstance<SmallClass>(() => new SmallClass()); | |
private static void SmallClassFromExpression() | |
=> MakeInstance<SmallClass>(smallClassConstructor); | |
private static void LargeClassWithConstraint() | |
=> MakeInstance<LargeClass>(); | |
private static void LargeClassWithProvider() | |
=> MakeInstance<LargeClass>(() => new LargeClass()); | |
private static void LargeClassFromExpression() | |
=> MakeInstance<LargeClass>(largeClassConstructor); | |
private static void MakeInstance<T>() where T : new() | |
{ | |
T t = new T(); | |
UseValue(t); | |
} | |
private static void MakeInstance<T>(Func<T> provider) where T : new() | |
{ | |
T t = provider(); | |
UseValue(t); | |
} | |
private static void UseValue<T>(T instance) | |
{ | |
// Do nothing... | |
} | |
// -------------- INFRASTRUCTURE BELOW HERE -------------- | |
const int Iterations = 100000000; | |
static void Main() | |
{ | |
Console.WriteLine("Environment: CLR {0} on {1}", Environment.Version, Environment.OSVersion); | |
// Warm up | |
RunTests(1, false, 0); | |
int maxMethodLength = Tests.Select(x => x.Method.Name.Length).Max(); | |
// Real thing | |
RunTests(Iterations, true, maxMethodLength); | |
} | |
static void RunTests(int count, bool displayResults, int maxLength) | |
{ | |
foreach (Action action in Tests) | |
{ | |
Stopwatch sw = Stopwatch.StartNew(); | |
for (int i = 0; i < count; i++) | |
{ | |
action(); | |
} | |
sw.Stop(); | |
if (displayResults) | |
{ | |
Console.WriteLine("{0}: {1}ms", action.Method.Name.PadRight(maxLength), | |
((int)sw.ElapsedMilliseconds).ToString().PadLeft(6)); | |
} | |
GC.Collect(); | |
GC.WaitForPendingFinalizers(); | |
GC.Collect(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment