Sunday 23 October 2016

Object copying speed comparison

       I've been wondering about speed differences in execution of property copying code, which is usually used/found in the adapter pattern implementation. The answers are obviously in stackoverflow and in various blogs. But I thought about pushing it a bit further and comparing speeds of different approaches to this issue.

Bear in mind different ways of doing the same thing have advantages and disadvantages and each way has different caveats. I've selected a couple of approaches, there are many which I've either missed or disregarded. Some of the listed methods have minimal differences between them - or would never be used in production code.

As a common use case for all I've selected copying data between a data transfer object (DTO) object and a View Model object.
  1. ManualMap - an ordinary property by property copying of whatever is in the object. Most often this is how it's done manually. Uses a foreach loop to loop through the objects.
  2. ManualForArrayMap - takes in an array of Dtos and uses a for loop. It could use a list as well.
  3. LinqMap - same as the foreach one but uses Linq to loop through the items.
  4. AutoMapperMap - uses automapper and foreach loop to loop through all the items
  5. AutoMapperLinqMap - similarly as above but uses Linq
  6. AutoMapperCollectionMap - maps the whole collection in one go instead of looping through the items and mapping one by one.
  7. ILMap - uses Emitted code which is cached as a delegate. Generic.
  8. ExpressionMap - uses expressions to bind properties of the objects. Generic.
  9. ReflectionOrderedPropertiesCopy - uses reflection with the assumption that the properties are ordered. Generic.
  10. ReflectionPropertySearchCopy - uses reflection and searches for each property within the object by name. Generic.
  11. ParallelForEachManualMap - uses a partitioner and a parallel foreach loop to split the collection into separate ranges.
  12. ParallelLinqMap - parallel linq with the use of AsParallel method. Checked a couple of times with different degrees of parallelism set.
The slowest out of these were the ones which use reflection (9 and 10), I haven't added them in the comparison cause numbers were off the chart. 7 and 8 use reflection as well but only when building the lookup - the time required for it is not taken into consideration, similarly as AutoMapper configuration.

To check the timings I've used DotNetBenchmark library, I've run it in release outside of Visual Studio to have fairly correct results. All the results below are actually a median taken out of multiple runs of the same method.

Below you can see the comparison of timings for different numbers of DTOs fed into the methods, all of these timings are in nanoseconds.

Comparison of timings.
Next I've created a chart based on the above.


There are some obvious takeaways above. I'll go into more details in the next post.

I'm pretty sure I have missed something or introduced some errors in the code - if you notice anything feel free to let me know. The code itself is sometimes under optimized and sometimes over optimized - but it was not the point of this specific post - it was more getting the general feeling of how fast can this boilerplate code run.

Links:
Github with sources for the comparison project: https://github.com/simonkatanski/speedtest/