[CSHARP-750] Improve performance of serialization/deserialization of types serialized as BSON arrays Created: 05/Jun/13 Updated: 27/Jul/13 Resolved: 13/Jul/13 |
|
| Status: | Closed |
| Project: | C# Driver |
| Component/s: | Performance |
| Affects Version/s: | 1.8.1 |
| Fix Version/s: | 1.8.2 |
| Type: | Improvement | Priority: | Minor - P4 |
| Reporter: | Dmitry Naumov | Assignee: | Robert Stam |
| Resolution: | Done | Votes: | 1 |
| Labels: | None | ||
| Remaining Estimate: | Not Specified | ||
| Time Spent: | Not Specified | ||
| Original Estimate: | Not Specified | ||
| Environment: |
Windows 7 Professional SP1 x64 |
||
| Attachments: |
|
| Backwards Compatibility: | Fully Compatible |
| Description |
|
When serializing array of value types there is no need to lookup for serializer for every item, because it is homogeneous. This saves us some cpu cycles but most benefit may be achieved when multiple threads are doing serialization, like in my multi-threaded insert benchmark. The suggest fix allows to avoid extra-contention on ReaderWriterLockSlim inside BsonSerializer.
|
| Comments |
| Comment by auto [ 09/Jul/13 ] | |||||||||||||||||||||
|
Author: {u'username': u'rstam', u'name': u'rstam', u'email': u'robert@10gen.com'}Message: | |||||||||||||||||||||
| Comment by auto [ 09/Jul/13 ] | |||||||||||||||||||||
|
Author: {u'username': u'rstam', u'name': u'rstam', u'email': u'robert@10gen.com'}Message: | |||||||||||||||||||||
| Comment by auto [ 09/Jul/13 ] | |||||||||||||||||||||
|
Author: {u'username': u'DmitryNaumov', u'name': u'Dmitry Naumov', u'email': u'dnaumov@paladyne.com'}Message: | |||||||||||||||||||||
| Comment by Dmitry Naumov [ 17/Jun/13 ] | |||||||||||||||||||||
|
I've updated pull request, now it contains optimizations for both serialization and deserialization. I also thought about covering such case: | |||||||||||||||||||||
| Comment by Chad Kreimendahl [ 13/Jun/13 ] | |||||||||||||||||||||
|
I suppose I'm speaking more of DEserialization, but bunched it with "serialization" as a whole. Our mongo machines are physically separate from our web servers. The mongo servers never really use more than 4-5% cpu [each], even when half a dozen web servers are being load tested. When we run the load test with a performance profiler enabled on the web site (IIS8), the vast majority of the CPU time used is in deserialization of objects coming out of mongo. We utilize some in-memory short-term caching to get around having to re-deserialize the same objects multiple times on a request, but still see that as the most major bottleneck. In all honesty, we know it's always going to be the largest resource hog, which is why even minor improvements in its performance will go a very long way to reducing our need to scale. I was only suggesting that some of the recent improvements made to other libraries for performance could be re-used [if legal] to improve the deserialization performance of the mongo.C# driver. Interestingly enough, Json.NET supports BSON, so it may be relatively easy to integrate by wrapping it with your customizations, so that future performance improvements to Json.NET automatically end up working in your code. It's really just an idea I had. There may be several reasons [political, security], that you don't want to simply integrate with a non-mongo-controlled third party open source library. Fortunately it's got an MIT license, so it can be copied without much headache. | |||||||||||||||||||||
| Comment by Robert Stam [ 13/Jun/13 ] | |||||||||||||||||||||
|
You certainly could do that. We're not going to be working on this just yet, so you have time to submit a new pull request. Thanks! | |||||||||||||||||||||
| Comment by Dmitry Naumov [ 13/Jun/13 ] | |||||||||||||||||||||
|
Robert, | |||||||||||||||||||||
| Comment by Dmitry Naumov [ 13/Jun/13 ] | |||||||||||||||||||||
|
Chad, | |||||||||||||||||||||
| Comment by Chad Kreimendahl [ 12/Jun/13 ] | |||||||||||||||||||||
|
Is it worthwhile to look at what newtonsoft/json.net has done recently in their serialization code that has dramatically improved its performance beyond where serviceStack is? Because mongo is so performant, our bottleneck (or location requiring most scalability) is our web site. Serialization is the vast majority of the CPU utilization, so focusing here and incorporating what others have done (as you guys have done very well in the past), could be good to do again. | |||||||||||||||||||||
| Comment by Robert Stam [ 11/Jun/13 ] | |||||||||||||||||||||
|
Thanks for the additional comments. We are looking to centralize all array-like serialization into a common base class, at which point we can make as many optimizations as we want without having to copy and paste them to all the other array-like serializers (the 10 or so listed earlier). We can definitely optimize value types separately from reference types. We won't forget about the Utf8Encoding change either. The plan is to merge your pull request and make further changes from there. | |||||||||||||||||||||
| Comment by Dmitry Naumov [ 11/Jun/13 ] | |||||||||||||||||||||
|
A few things to mention: 1. for-loop is penalized by boundaries check on each iteration. | |||||||||||||||||||||
| Comment by Robert Stam [ 11/Jun/13 ] | |||||||||||||||||||||
|
A better version of the alternative change proposed two comments ago is:
This version emphasizes that what we're doing is optimizing the selection of the serializer, and only has one call to Serialize (using whatever serializer was chosen). It also abandons the numeric for loop in favor of foreach. Presumably someone thought that for was faster than foreach, but I did some benchmarks and they are virtually identical, so the simpler form is preferable. | |||||||||||||||||||||
| Comment by Robert Stam [ 11/Jun/13 ] | |||||||||||||||||||||
|
There are several other serializers that would benefit from a similar optimization:
| |||||||||||||||||||||
| Comment by Robert Stam [ 11/Jun/13 ] | |||||||||||||||||||||
|
A similar change based on the same idea is:
This alternative would benefit homogenous arrays of all types, whether they are value types or not. | |||||||||||||||||||||
| Comment by Dmitry Naumov [ 10/Jun/13 ] | |||||||||||||||||||||
|
This issue was hidden by | |||||||||||||||||||||
| Comment by Craig Wilson [ 05/Jun/13 ] | |||||||||||||||||||||
|
Thanks Dmitry. We'll definitely take a look. | |||||||||||||||||||||
| Comment by Dmitry Naumov [ 05/Jun/13 ] | |||||||||||||||||||||
|
With another fix removing per-call creation of UTF8Encoding, the numbers are even better:
| |||||||||||||||||||||
| Comment by Dmitry Naumov [ 05/Jun/13 ] | |||||||||||||||||||||
|
https://github.com/mongodb/mongo-csharp-driver/pull/159 Benchmark results for inserting document with array of 1000 ints:
|