Share

Tags

Disclaimer

This is a personal blog. The opinions expressed here represent my own and not those of my employer, nor current or previous. All content is published "as is", without warranty of any kind and I don't take any responsibility and can't be liable for any claims, damages or other liabilities that might be caused by the content.

Structurizer improvements

Structurizer turns your object graph into a key-value representation (read more in previous post). When building the key-value representation it leaves out all null values and keeps the actual values. Each value is contained in a StructureIndex. Since it is generated dynamically each value is stored as an object. So Structurizer does not not convert them into string representation a'la JSON or something. But what if it did? I started to attack the IL-code generation to see if my idea could be effectful. So instead of representing each value using an object, the idea was to convert all value types to strings to get rid of the boxing and unboxing associated with them. When doing this I finally got a chance to have a look at BenchmarkDotNet. As a tool for seeing the metrics before and after my changes. Just to get an idea of something similar, I also benchmarked the process of serializing and deserializing the same object graph using Newtonsoft's JSON.Net.

Benchmarking JSON.Net as well

This is a bit like comparing apples with pears, but I can see people questioning the metrics of Structurizer, while at the same time they are using JSON.Net to serialize and deserialize back and forth between objects and JSON.

JSON.Net - Just for fun

Note. Again. This was just included so that you could get an idea of metrics around something similar that you might be doing in various places in your code base. Like the process of serializing and deserializing the same object graph using Newtonsoft's JSON.Net.

What change made the biggest difference?

The code base that this comes from is a few years old. And in there, there were a naive optimisation attempt. The StructureBuilder was using Parallel.For to create structures. But this only kicked in if the number of structures where 100 or more (no idea where that number came from).

Parallel.For was also used in the StructureIndexFactory in which the StructureIndexes are created. So one master parallel flow calling into a child parallel flow that in turn created pre-sized arrays represented by IEnumerable<IStructureIndex>[] which in the end wasn't returned as is, but instead null values where filtered out and returned as an array:

For now, this implicit construct has been replaced with a simple List<IStructureIndex>. And population of values and exclusion of null values are done within a simple sequential for-loop instead. This was the change that had the biggest impact on both time and memory allocation.