Created
October 3, 2010 01:49
-
-
Save caleb-vear/608184 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Testing cached delegate wireup Event Handler Performance with 1,000,000 iterations | |
| Time to build handler cache 3 ms or 6,548 ticks | |
| Completed 1,000,000 iterations in 7,434 ms | |
| Average Time is 0 ms or 14 ticks | |
| Press enter to exit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| private void Apply(Type eventType, TDomainEvent domainEvent) | |
| { | |
| string expectedMethodName = "On" + eventType.Name.Substring(0, eventType.Name.Length - "Event".Length); | |
| var methodInfo = GetType().GetMethod(expectedMethodName, BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { eventType }, null); | |
| if (methodInfo == null) | |
| throw new UnregisteredDomainEventException(string.Format("The requested domain event '{0}' is not registered in '{1}'", eventType.FullName, GetType().FullName)); | |
| methodInfo.Invoke(this, new object[] { domainEvent }); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Testing basic reflection wireup Event Handler Performance with 1,000,000 iterations | |
| Completed 1,000,000 iterations in 21,427 ms | |
| Average Time is 0 ms or 39 ticks | |
| Press enter to exit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| private void Apply(Type eventType, TDomainEvent domainEvent) | |
| { | |
| Action<object, IDomainEvent> handler; | |
| if (_registeredEvents.TryGetValue(eventType, out handler) == false) | |
| throw new UnregisteredDomainEventException(string.Format("The requested domain event '{0}' is not registered in '{1}'", eventType.FullName, GetType().FullName)); | |
| handler(this, domainEvent); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public AbstractAggregateRoot() | |
| { | |
| _registeredEvents = EventHandlerMappings.GetHandlersFor(GetType()); | |
| _appliedEvents = new List<TDomainEvent>(); | |
| } | |
| private void Apply(Type eventType, TDomainEvent domainEvent) | |
| { | |
| MethodInfo methodInfo; | |
| if (_registeredEvents.TryGetValue(eventType, out methodInfo) == false) | |
| throw new UnregisteredDomainEventException(string.Format("The requested domain event '{0}' is not registered in '{1}'", eventType.FullName, GetType().FullName)); | |
| methodInfo.Invoke(this, new object[] { domainEvent }); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Testing cached reflection wireup Event Handler Performance with 1,000,000 iterations | |
| Time to build handler cache 2 ms or 4,167 ticks | |
| Completed 1,000,000 iterations in 15,798 ms | |
| Average Time is 0 ms or 29 ticks | |
| Press enter to exit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public static class EventHandlerMappings | |
| { | |
| private static readonly object handlerMapLock = new object(); | |
| private static Dictionary<Type, Dictionary<Type, Action<object, IDomainEvent>>> handlerMaps = new Dictionary<Type, Dictionary<Type, Action<object, IDomainEvent>>>(); | |
| public static void ClearHandlerCache() | |
| { | |
| lock (handlerMapLock) | |
| handlerMaps.Clear(); | |
| } | |
| public static IDictionary<Type, Action<object, IDomainEvent>> GetHandlersFor(Type t) | |
| { | |
| lock (handlerMapLock) | |
| { | |
| Dictionary<Type, Action<object, IDomainEvent>> result = null; | |
| if (handlerMaps.TryGetValue(t, out result) == false) | |
| { | |
| result = AddHandlerMapFor(t); | |
| handlerMaps.Add(t, result); | |
| } | |
| return result; | |
| } | |
| } | |
| private static Dictionary<Type, Action<object, IDomainEvent>> AddHandlerMapFor(Type t) | |
| { | |
| Stopwatch watch = new Stopwatch(); | |
| watch.Start(); | |
| var handlerMethods = from method in t.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic) | |
| let parameters = method.GetParameters() | |
| where method.Name.StartsWith("On") | |
| && parameters.Length == 1 | |
| && typeof(IDomainEvent).IsAssignableFrom(parameters[0].ParameterType) | |
| select new { EventType = parameters[0].ParameterType, Method = method }; | |
| var result = new Dictionary<Type, Action<object, IDomainEvent>>(); | |
| foreach (var handler in handlerMethods) | |
| { | |
| var genericParams = new Type[] { t, handler.EventType }; | |
| var actionType = typeof(Action<,>).MakeGenericType(genericParams); | |
| var action = Delegate.CreateDelegate(actionType, handler.Method); | |
| var createDelegateMethod = typeof(EventHandlerMappings).GetMethod("CreateHandlerInvokeDelegate", BindingFlags.NonPublic | BindingFlags.Static) | |
| .MakeGenericMethod(genericParams); | |
| result.Add(handler.EventType, (Action<object, IDomainEvent>)createDelegateMethod.Invoke(null, new object[] { action})); | |
| }; | |
| watch.Stop(); | |
| Console.WriteLine("Time to build handler cache {0:#,0} ms or {1:#,0} ticks", watch.ElapsedMilliseconds, watch.ElapsedTicks); | |
| return result; | |
| } | |
| private static Action<object, IDomainEvent> CreateHandlerInvokeDelegate<TEventSource, TEvent>(Action<TEventSource, TEvent> action) | |
| { | |
| return delegate(object obj, IDomainEvent e) | |
| { | |
| action((TEventSource)obj, (TEvent)e); | |
| }; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| private void Apply(Type eventType, TDomainEvent domainEvent) | |
| { | |
| Action<TDomainEvent> handler; | |
| if (!_registeredEvents.TryGetValue(eventType, out handler)) | |
| throw new UnregisteredDomainEventException(string.Format("The requested domain event '{0}' is not registered in '{1}'", eventType.FullName, GetType().FullName)); | |
| handler(domainEvent); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Testing Manual Wireup Event Handler Performance with 1,000,000 iterations | |
| Completed 1,000,000 iterations in 10,463 ms | |
| Average Time is 0 ms or 19 ticks | |
| Press enter to exit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| class Program | |
| { | |
| public const int Iterations = 1000000; | |
| static void Main(string[] args) | |
| { | |
| Console.WriteLine("Testing Manual Wireup Event Handler Performance with {0:#,0} iterations", Iterations); | |
| // Dry run so that the code is JITed before we test. | |
| RunTest("Dry Run"); | |
| List<Account> accounts = new List<Account>(Iterations); | |
| Stopwatch watch = new Stopwatch(); | |
| watch.Start(); | |
| for (int i = 0; i < Iterations; i++) | |
| accounts.Add(RunTest(string.Format("Account {0}", i))); | |
| watch.Stop(); | |
| Console.WriteLine("Completed {0:#,0} iterations in {1:#,0} ms", Iterations, watch.ElapsedMilliseconds); | |
| Console.WriteLine("Average Time is {0:#,0} ms or {1:#,0} ticks", watch.ElapsedMilliseconds / (double)Iterations, watch.ElapsedTicks / (double)Iterations); | |
| Console.WriteLine("\nPress enter to exit"); | |
| Console.ReadLine(); | |
| } | |
| private static Account RunTest(string accountName) | |
| { | |
| IEventProvider<IDomainEvent> account = new Account(); | |
| account.LoadFromHistory(new IDomainEvent[] | |
| { | |
| new AccountCreatedEvent(accountName), | |
| new DepositEvent(1000), | |
| new WithdrawEvent(300), | |
| new WithdrawEvent(250), | |
| new DepositEvent(35.90M), | |
| new WithdrawEvent(10.80M) | |
| }); | |
| return account as Account; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment