mongodb/mongo-csharp-driver — pull request #122 by optimiz3 (2012-07-31 22:23:57+00:00)
Title: Improve Bson Deserialization Performance by 10-15% (Refactor Discriminator Code)

1. Ongoing profiling of the driver revealed that refactoring discriminator handling code was a strong candidate for performance improvement.
a. A fair bit of time was being spent in Type verification, DiscriminatorConvention lookup, Serializer lookup, and the associated locking code.
b. Of note, discriminator code was being executed during deserialization regardless of whether it was appropriate for the Type.
i. Specifically, only unsealed class types can have useful discriminators in .Net as only these types can be inherited.
ii. Additionally, the implementation of the StandardDiscriminator was always evaluating for primitive types, however the only nominal type that is assignable at the CLR layer is System.Object, making much of the computation unnecessary.
2. To achieve performance and maintainability improvements the following was done:
a. Factor out discriminator code into a DiscriminatorSerializer wrapper serializer.
b. Only wrap serializers that can be discriminated.
c. Factored out previous performance related serializer caching work into a SerializerHolder class
i. Replaced lots of duplicate discriminator lookup -> serializer lookup -> serializer caching code with this class.
ii. Also applied this class to generic collections that had been missed in previous rounds of performance improvement as they were not covered by benchmarks.
iii. In several cases this reduced class size as these holders could be made static relative to the generic class types.
3. To improve the performance of discriminator lookups the following was done:
a. Combine BsonSerializer.__discriminatedTypes and BsonSerializer.__typesWithRegisteredKnownTypes into a single dictionary.
b. Make accesses to the new dictionary only require a lock for updating
4. Another minor performance improvement to reduce the overhead of BsonClassMapSerializer.DeserializeMember (one of the hottest methods)
a. Move the try/catch setup to outside the member loop in BsonClassMapSerializer.Deserialize, this way the try/catch only needs to be setup once per instance rather than once per member.
5. Another minor performance improvement to reduce the overhead of DictionaryGenericSerializer
a. Call dictionary.Add(key, value) instead of .Add(keyValuePair) as the second requires cloning a struct on the stack as the struct is passed by value
6. Net is that classes with primitive properties (i.e. almost all) benefit from this, as well as all generic collection types.
7. Finally, care was taken not to disturb any publicly facing APIs, as the API was to make improvements turnkey.

Raw profiling data, I can provide hard VS profiler results and benchmark code as well if needed.

Iterations	master	optimiz3	Improvement
25000	10.3441722	9.3571325	10%
25000	10.4369589	9.4071719	10%
25000	10.5356442	9.4646407	10%
25000	10.4389251	9.409648367	10%