After discussion today about how slow are events I've tried to write a small test to see how slow our events are. It was almost obvious for me that because of compile-time code weaving there should be no big overheads in use of aspects to manage events (of course when they are used properly, it is always easy to misuse things (wink)). Below are results, it looks like it was pretty slow, but we did it, by using Reflection. Taking into account that we did not do optimization at all I did only minimal optimization, actually removed our custom NotifyPropertyChangeArgs implementation and used standard System.ComponentModel.NotifyPropertyChangeEventArgs. As result OldValue and NewValue disappeared. If we will need them - we will have to extend an aspect attribute to use PropertyChanging events. Also we probably will need something similarto implement IEditableObject (transactional object editing) or for implementation of Memento Design Pattern (to implement Undo / Redo). The main advantage is - reuse. Less code is always good plus looking on videos / conferences it seems to be a current direction where programming languages moving to (DSL, AOP).

// Before optimization
// -------------------

NotifyPropertyChangedAttributeTest.SlowDownBecauseOfPropertyChangeEventsShouldBeLessThan250Percent : Failed
1375 [7] INFO 100 000 changes without NotifyPropertyChanged: 125 milliseconds
1421 [7] INFO 100 000 changes with NotifyPropertyChanged: 750 milliseconds
1421 [7] INFO (warning) >>> 500% slower <<< (warning)

NUnit.Framework.AssertionException: Expected: less than or equal to 40.0d
But was: 500.0d

// After Optimization (remove use of reflection in aspect and remove OldValue / NewValue in aspect - use standard .NET 3.5 implementation)
// ------------------

828 [7] INFO 100 000 changes without NotifyPropertyChanged: 140.625 milliseconds
875 [7] INFO 100 000 changes with NotifyPropertyChanged: 187.5 milliseconds
875 [7] INFO >>> 33% slower <<< ... 15x speedup (smile)

Actually it varies ~10-50%. Have no idea why it is slower / faster, probably some .NET or ReSharper pre-compiled bytecode tricks.

33% is a very good price for the functionality we get back.

I guess we will have to write similar performance tests for CollectionChange event.

By the way, the main current bottleneck in the Network classes is an EventedListView, we will need to get rid of it ASAP by replacing it with IEnumerable<...>, only one issue remains is that feature providers will need to be informed somehow that features in collection were changed.

2 Comments

  1. Unknown User (muurman)

    Please note that the biggest performance penaltly/increase can be get by not creating events when we don't need em. If we do something in a eventhandler the time spent to create the event is probably very small compared to the we spent in the handler (draw refresh etc)

    1. Unknown User (don) AUTHOR

      Fully agree, but we also should not loose them when they need to be sent. There are probably several ways to handle it, e.g. ILayer has a property RefreshRequired so that map won't be refreshed when event is sent. Use timer to make sure map or any other event handler won't be refreshed 10k times.

      What I was thinking about is to implement IEditableObject in those classes where events are critical and then disable all events to the outside world in BeginEdit() + send Refresh in the EndEdit(). However if object being edited is a very complex on - it still may be not a good idea to refresh everything. When you have a 2 maps open and every map contains network with 10 layers and only 1 cross-section is changed - there is no need to refresh 20 layers but just 1.