Skip to content

Instantly share code, notes, and snippets.

@iwillspeak
Last active February 10, 2018 08:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iwillspeak/2f97766aef7a1f44f5c4feb89f65ffd8 to your computer and use it in GitHub Desktop.
Save iwillspeak/2f97766aef7a1f44f5c4feb89f65ffd8 to your computer and use it in GitHub Desktop.
Demonstration of caching of derived type information using the curiously recurring template pattern
root = true
[*.cs]
indent_style = space
indent_size = 4
bin/
obj/
BenchmarkDotNet.Artifacts/
using System;
using System.Reflection;
using System.Linq;
using System.Collections.Concurrent;
using System.Collections.Generic;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
namespace crtp
{
using foo;
using bar;
using baz;
namespace foo
{
public class FooBase
{
public FooBase()
{
_props = CrtpBench.GetProperties(GetType());
}
private IDictionary<string, PropertyInfo> _props;
}
public class Foo : FooBase
{
public string F { get; }
public int B { get; }
}
}
namespace bar
{
public class BarBase<T>
{
private static IDictionary<string, PropertyInfo> Props = CrtpBench.GetProperties(typeof(T));
}
public class Bar : BarBase<Bar>
{
public string F { get; }
public int B { get; }
}
}
namespace baz
{
public class BazBase
{
public BazBase()
{
_props = TypeProps.GetOrAdd(GetType(), CrtpBench.GetProperties);
}
private IDictionary<string, PropertyInfo> _props;
private static ConcurrentDictionary<Type, IDictionary<string, PropertyInfo>> TypeProps =
new ConcurrentDictionary<Type, IDictionary<string, PropertyInfo>>();
}
public class Baz : BazBase
{
public string F { get; }
public int B { get; }
}
}
public class Program
{
public static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<CrtpBench>();
}
}
[MemoryDiagnoser]
public class CrtpBench
{
public static IDictionary<string, PropertyInfo> GetProperties(Type t) =>
t.GetMembers()
.Where(mi => mi.MemberType==MemberTypes.Property)
.Cast<PropertyInfo>()
.ToDictionary(prop => prop.Name);
[Benchmark]
public Foo Standard() => new Foo();
[Benchmark]
public Baz StaticCache() => new Baz();
[Benchmark]
public Bar Crtp() => new Bar();
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.10.12" />
</ItemGroup>
</Project>
@iwillspeak
Copy link
Author

Execute with

$ dotnet run --configuration Release

@iwillspeak
Copy link
Author

iwillspeak commented Feb 9, 2018

// * Summary *

BenchmarkDotNet=v0.10.12, OS=macOS 10.13.2 (17C88) [Darwin 17.3.0]
Intel Core i7-4980HQ CPU 2.80GHz (Haswell), 1 CPU, 8 logical cores and 4 physical cores
.NET Core SDK=2.0.0
  [Host]     : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT
  DefaultJob : .NET Core 2.0.0 (Framework 4.6.00001.0), 64bit RyuJIT


      Method |         Mean |     Error |    StdDev |  Gen 0 | Allocated |
------------ |-------------:|----------:|----------:|-------:|----------:|
    Standard | 1,153.020 ns | 9.1427 ns | 7.1380 ns | 0.0954 |     600 B |
 StaticCache |    40.069 ns | 0.5370 ns | 0.5023 ns | 0.0165 |     104 B |
        Crtp |     4.095 ns | 0.1147 ns | 0.1072 ns | 0.0051 |      32 B |

// * Hints *
Outliers
  CrtpBench.Standard: Default -> 3 outliers were removed

// * Legends *
  Mean      : Arithmetic mean of all measurements
  Error     : Half of 99.9% confidence interval
  StdDev    : Standard deviation of all measurements
  Gen 0     : GC Generation 0 collects per 1k Operations
  Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
  1 ns      : 1 Nanosecond (0.000000001 sec)

// * Diagnostic Output - MemoryDiagnoser *

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment