kryo
kryo copied to clipboard
ArrayClassResolver
- in terms of functionality, ArrayClassResolver is completely equivalent to DefaultClassResolver.
- 60% faster in module only comparison.
- 17% faster in a case where new module is good.
- even or a bit faster in existing benchmarks.
- fully tested by existing all test cases.
ArrayClassResolver vs DefaultClassResolver in existing benchmarks and a new benchmark deserializeCollection().
the benchmark of deserializeCollection() means the benchmark where new module is good as mentioned above. I said 17%, but when I did it over again, it was 22%.
Benchmark (chunked) (objectType) (references) Mode Cnt Score Error Units
ArrayClassResolverBenchmark.compatible true sample true thrpt 51008.685 ops/s +20%
ArrayClassResolverBenchmark.compatible true sample false thrpt 50357.070 ops/s +9%
ArrayClassResolverBenchmark.compatible true media true thrpt 34267.230 ops/s -4%
ArrayClassResolverBenchmark.compatible true media false thrpt 38989.524 ops/s +5%
ArrayClassResolverBenchmark.compatible false sample true thrpt 61167.441 ops/s +2%
ArrayClassResolverBenchmark.compatible false sample false thrpt 58323.752 ops/s +9%
ArrayClassResolverBenchmark.compatible false media true thrpt 54692.277 ops/s +3%
ArrayClassResolverBenchmark.compatible false media false thrpt 64503.562 ops/s +0%
ArrayClassResolverBenchmark.custom N/A sample true thrpt 218948.558 ops/s +22%
ArrayClassResolverBenchmark.custom N/A sample false thrpt 280062.482 ops/s -9%
ArrayClassResolverBenchmark.custom N/A media true thrpt 219362.428 ops/s +7%
ArrayClassResolverBenchmark.custom N/A media false thrpt 296784.221 ops/s +6%
ArrayClassResolverBenchmark.deserializeCollection N/A N/A N/A thrpt 3512.887 ops/s +22%
ArrayClassResolverBenchmark.field N/A sample true thrpt 140556.711 ops/s -2%
ArrayClassResolverBenchmark.field N/A sample false thrpt 176154.086 ops/s +0%
ArrayClassResolverBenchmark.field N/A media true thrpt 101946.746 ops/s -5%
ArrayClassResolverBenchmark.field N/A media false thrpt 136236.000 ops/s +1%
ArrayClassResolverBenchmark.tagged true sample true thrpt 62581.911 ops/s +5%
ArrayClassResolverBenchmark.tagged true sample false thrpt 70382.768 ops/s -3%
ArrayClassResolverBenchmark.tagged true media true thrpt 43998.954 ops/s +15%
ArrayClassResolverBenchmark.tagged true media false thrpt 45048.492 ops/s -4%
ArrayClassResolverBenchmark.tagged false sample true thrpt 118627.159 ops/s -3%
ArrayClassResolverBenchmark.tagged false sample false thrpt 155404.408 ops/s +11%
ArrayClassResolverBenchmark.tagged false media true thrpt 95521.280 ops/s +5%
ArrayClassResolverBenchmark.tagged false media false thrpt 109023.381 ops/s -12%
ArrayClassResolverBenchmark.version N/A sample true thrpt 138807.383 ops/s +0%
ArrayClassResolverBenchmark.version N/A sample false thrpt 158361.668 ops/s -5%
ArrayClassResolverBenchmark.version N/A media true thrpt 100543.566 ops/s +1%
ArrayClassResolverBenchmark.version N/A media false thrpt 130043.209 ops/s -6%
FieldSerializerBenchmark.compatible true sample true thrpt 42212.839 ops/s
FieldSerializerBenchmark.compatible true sample false thrpt 46023.033 ops/s
FieldSerializerBenchmark.compatible true media true thrpt 35397.962 ops/s
FieldSerializerBenchmark.compatible true media false thrpt 36918.318 ops/s
FieldSerializerBenchmark.compatible false sample true thrpt 59724.571 ops/s
FieldSerializerBenchmark.compatible false sample false thrpt 62531.128 ops/s
FieldSerializerBenchmark.compatible false media true thrpt 53059.577 ops/s
FieldSerializerBenchmark.compatible false media false thrpt 64318.756 ops/s
FieldSerializerBenchmark.custom N/A sample true thrpt 179181.025 ops/s
FieldSerializerBenchmark.custom N/A sample false thrpt 306796.991 ops/s
FieldSerializerBenchmark.custom N/A media true thrpt 204973.342 ops/s
FieldSerializerBenchmark.custom N/A media false thrpt 278362.471 ops/s
FieldSerializerBenchmark.deserializeCollection N/A N/A N/A thrpt 2872.603 ops/s
FieldSerializerBenchmark.field N/A sample true thrpt 142358.449 ops/s
FieldSerializerBenchmark.field N/A sample false thrpt 175401.411 ops/s
FieldSerializerBenchmark.field N/A media true thrpt 107239.618 ops/s
FieldSerializerBenchmark.field N/A media false thrpt 134269.230 ops/s
FieldSerializerBenchmark.tagged true sample true thrpt 59098.784 ops/s
FieldSerializerBenchmark.tagged true sample false thrpt 72018.054 ops/s
FieldSerializerBenchmark.tagged true media true thrpt 38062.676 ops/s
FieldSerializerBenchmark.tagged true media false thrpt 46442.003 ops/s
FieldSerializerBenchmark.tagged false sample true thrpt 121174.659 ops/s
FieldSerializerBenchmark.tagged false sample false thrpt 138890.530 ops/s
FieldSerializerBenchmark.tagged false media true thrpt 90208.077 ops/s
FieldSerializerBenchmark.tagged false media false thrpt 122979.294 ops/s
FieldSerializerBenchmark.version N/A sample true thrpt 138958.036 ops/s
FieldSerializerBenchmark.version N/A sample false thrpt 165104.030 ops/s
FieldSerializerBenchmark.version N/A media true thrpt 98666.305 ops/s
FieldSerializerBenchmark.version N/A media false thrpt 138138.066 ops/s
ArrayClassResolver makes sense only when idToRegistration is used. Some benchmarks of ArrayClassResolverBenchmark may not use ArrayClassResolver at all.
ArrayClassResolver is generally superior to DefaultClassResolver, and may replace the DefaultClassResolver's idToRegistration implementation, If you agree on this benchmark result.
@lifeinwild: Thanks for the PR!
Your solution is interesting, but I don't think it's generic enough to be included as an additional class resolver in Kryo. Users have to be aware of how to use the new class resolver, e.g. high IDs would lead to very large array sizes. Changes to registrations rebuild the entire array. The current map-based approach doesn't have these issues.
It would probably make more sense to cache registrations in CollectionSerializer
and MapSerializer
in case the concrete type is not known, but all elements are of the same type. In case of collections, the default class resolver shouldn't even do a lookup right now because it memoizes the last seen class. Where do your performance improvements come from in that case?
I confirmed a very funny behavior about DefaultClassResolver. When kryo deserialize a Map, the order is a key, a value, a key, a value over and over. By the way, the existing cache system of memoizedClass remembers the last deserialized class. so, when it deserialize a value, memoizedClass is the class of key. when it deserialize a key, memoizedClass is the class of value. So the cache system is not working at all.
Postscript: The existing cache system of memoizedClass is very efficient in some cases, but in deserializing Map, memoizedClassId and memoizedClassIdValue of DefaultClassResolver.java line 144 readClass() don't make sense.
The ArrayClassResolver javadoc provides some notes on using it. In most cases, class IDs are sequential number, and I thought there is no problem.
There are a few cases where DefaultClassResolver beats ArrayClassResolver. I imagine that it is when the cache system works effectively. If I implement memoizedClass cache system in ArrayClassResolver, ArrayClassResolver will win in all cases.
I compared again with the memoizedClass version about all the cases ArrayClassResolver lost. It reversed in almost all but one case. There may be a new case of losing. I should calculate that automatically.
Benchmark (chunked) (objectType) (references) Mode Cnt Score Error Units
ArrayClassResolverBenchmark.compatible true sample true thrpt 49597.815 ops/s
ArrayClassResolverBenchmark.compatible true sample false thrpt 53074.314 ops/s
ArrayClassResolverBenchmark.compatible true media true thrpt 31692.395 ops/s
ArrayClassResolverBenchmark.compatible true media false thrpt 38979.275 ops/s
ArrayClassResolverBenchmark.compatible false sample true thrpt 53767.859 ops/s
ArrayClassResolverBenchmark.compatible false sample false thrpt 61631.543 ops/s
ArrayClassResolverBenchmark.compatible false media true thrpt 53027.574 ops/s
ArrayClassResolverBenchmark.compatible false media false thrpt 60989.829 ops/s
ArrayClassResolverBenchmark.custom N/A sample true thrpt 176400.989 ops/s
ArrayClassResolverBenchmark.custom N/A sample false thrpt 246524.176 ops/s -8%
ArrayClassResolverBenchmark.custom N/A media true thrpt 211663.616 ops/s
ArrayClassResolverBenchmark.custom N/A media false thrpt 275782.541 ops/s
ArrayClassResolverBenchmark.deserializeCollection N/A N/A N/A thrpt 3205.649 ops/s
ArrayClassResolverBenchmark.field N/A sample true thrpt 130048.576 ops/s +3%
ArrayClassResolverBenchmark.field N/A sample false thrpt 173279.543 ops/s
ArrayClassResolverBenchmark.field N/A media true thrpt 103346.161 ops/s +4%
ArrayClassResolverBenchmark.field N/A media false thrpt 140181.352 ops/s
ArrayClassResolverBenchmark.tagged true sample true thrpt 64791.884 ops/s
ArrayClassResolverBenchmark.tagged true sample false thrpt 73984.768 ops/s +3%
ArrayClassResolverBenchmark.tagged true media true thrpt 38549.413 ops/s
ArrayClassResolverBenchmark.tagged true media false thrpt 48191.840 ops/s +7%
ArrayClassResolverBenchmark.tagged false sample true thrpt 111493.444 ops/s +1%
ArrayClassResolverBenchmark.tagged false sample false thrpt 142018.948 ops/s
ArrayClassResolverBenchmark.tagged false media true thrpt 89015.540 ops/s
ArrayClassResolverBenchmark.tagged false media false thrpt 110114.939 ops/s +7%
ArrayClassResolverBenchmark.version N/A sample true thrpt 128488.493 ops/s
ArrayClassResolverBenchmark.version N/A sample false thrpt 172444.250 ops/s +8%
ArrayClassResolverBenchmark.version N/A media true thrpt 97143.170 ops/s
ArrayClassResolverBenchmark.version N/A media false thrpt 128207.589 ops/s +3%
FieldSerializerBenchmark.compatible true sample true thrpt 46005.585 ops/s
FieldSerializerBenchmark.compatible true sample false thrpt 46322.016 ops/s
FieldSerializerBenchmark.compatible true media true thrpt 34642.254 ops/s
FieldSerializerBenchmark.compatible true media false thrpt 39603.196 ops/s
FieldSerializerBenchmark.compatible false sample true thrpt 49820.885 ops/s
FieldSerializerBenchmark.compatible false sample false thrpt 58956.236 ops/s
FieldSerializerBenchmark.compatible false media true thrpt 56375.139 ops/s
FieldSerializerBenchmark.compatible false media false thrpt 57274.959 ops/s
FieldSerializerBenchmark.custom N/A sample true thrpt 179100.628 ops/s
FieldSerializerBenchmark.custom N/A sample false thrpt 268510.473 ops/s
FieldSerializerBenchmark.custom N/A media true thrpt 211254.109 ops/s
FieldSerializerBenchmark.custom N/A media false thrpt 281465.594 ops/s
FieldSerializerBenchmark.deserializeCollection N/A N/A N/A thrpt 2830.052 ops/s
FieldSerializerBenchmark.field N/A sample true thrpt 126218.600 ops/s
FieldSerializerBenchmark.field N/A sample false thrpt 159265.709 ops/s
FieldSerializerBenchmark.field N/A media true thrpt 98983.875 ops/s
FieldSerializerBenchmark.field N/A media false thrpt 121946.268 ops/s
FieldSerializerBenchmark.tagged true sample true thrpt 60606.290 ops/s
FieldSerializerBenchmark.tagged true sample false thrpt 71257.698 ops/s
FieldSerializerBenchmark.tagged true media true thrpt 39080.604 ops/s
FieldSerializerBenchmark.tagged true media false thrpt 44798.157 ops/s
FieldSerializerBenchmark.tagged false sample true thrpt 109756.560 ops/s
FieldSerializerBenchmark.tagged false sample false thrpt 134438.393 ops/s
FieldSerializerBenchmark.tagged false media true thrpt 83588.046 ops/s
FieldSerializerBenchmark.tagged false media false thrpt 102539.020 ops/s
FieldSerializerBenchmark.version N/A sample true thrpt 130777.506 ops/s
FieldSerializerBenchmark.version N/A sample false thrpt 158775.275 ops/s
FieldSerializerBenchmark.version N/A media true thrpt 102672.418 ops/s
FieldSerializerBenchmark.version N/A media false thrpt 124018.380 ops/s
I did more benchmarking.
In most cases, ArrayClassResolver wins, but sometimes loses due to measurement errors. Even in the worst benchmarks, ArrayClassResolver has about 50% chance of beating DefaultClassResolver.
Another design idea is to support Map by two memoizedClasses in DefaultClassResolver. However, even with two memoizedClasses, the cache hit rate is limited in other than Map, and the cost of assign like memoizedClassId = classID is not negligible.
Pooling solves the problem of ArrayClassResolver.
Now the risk of reconstructing array is same of standard classes such as HashMap.
And the performance is balanced. win: 21/29 draw: 5/29 lose: 3/29 highest:+14% lowest:-3% ave:+3.55%
ArrayClassResolverBenchmark.compatible true sample true thrpt 10 47105.888 ± 5232.681 ops/s +8%
ArrayClassResolverBenchmark.compatible true sample false thrpt 10 50125.252 ± 3044.107 ops/s +6%
ArrayClassResolverBenchmark.compatible true media true thrpt 10 32791.623 ± 769.283 ops/s +2%
ArrayClassResolverBenchmark.compatible true media false thrpt 10 39642.747 ± 2394.012 ops/s +5%
ArrayClassResolverBenchmark.compatible false sample true thrpt 10 54706.812 ± 4795.753 ops/s +3%
ArrayClassResolverBenchmark.compatible false sample false thrpt 10 61608.488 ± 7240.204 ops/s +5%
ArrayClassResolverBenchmark.compatible false media true thrpt 10 56632.828 ± 6674.765 ops/s +3%
ArrayClassResolverBenchmark.compatible false media false thrpt 10 63894.499 ± 7132.353 ops/s +5%
ArrayClassResolverBenchmark.custom N/A sample true thrpt 10 188114.598 ± 18240.086 ops/s -0%
ArrayClassResolverBenchmark.custom N/A sample false thrpt 10 267678.803 ± 11254.795 ops/s +1%
ArrayClassResolverBenchmark.custom N/A media true thrpt 10 207370.629 ± 19057.415 ops/s +3%
ArrayClassResolverBenchmark.custom N/A media false thrpt 10 283463.184 ± 35439.475 ops/s +1%
ArrayClassResolverBenchmark.deserializeCollection N/A N/A N/A thrpt 10 3261.131 ± 230.145 ops/s +13%
ArrayClassResolverBenchmark.field N/A sample true thrpt 10 138623.813 ± 7986.628 ops/s +7%
ArrayClassResolverBenchmark.field N/A sample false thrpt 10 185814.162 ± 19044.019 ops/s +14%
ArrayClassResolverBenchmark.field N/A media true thrpt 10 108626.802 ± 12772.109 ops/s +6%
ArrayClassResolverBenchmark.field N/A media false thrpt 10 138741.228 ± 14569.221 ops/s +9%
ArrayClassResolverBenchmark.tagged true sample true thrpt 10 64186.029 ± 2906.871 ops/s +0%
ArrayClassResolverBenchmark.tagged true sample false thrpt 10 72422.581 ± 4791.915 ops/s -2%
ArrayClassResolverBenchmark.tagged true media true thrpt 10 38992.236 ± 5849.945 ops/s +5%
ArrayClassResolverBenchmark.tagged true media false thrpt 10 45419.492 ± 4482.847 ops/s +0%
ArrayClassResolverBenchmark.tagged false sample true thrpt 10 121140.945 ± 17324.226 ops/s +4%
ArrayClassResolverBenchmark.tagged false sample false thrpt 10 146101.103 ± 19635.822 ops/s +6%
ArrayClassResolverBenchmark.tagged false media true thrpt 10 85485.768 ± 6167.722 ops/s -0%
ArrayClassResolverBenchmark.tagged false media false thrpt 10 107103.143 ± 5890.400 ops/s +0%
ArrayClassResolverBenchmark.version N/A sample true thrpt 10 127367.297 ± 12304.918 ops/s -3%
ArrayClassResolverBenchmark.version N/A sample false thrpt 10 171983.482 ± 27063.498 ops/s +3%
ArrayClassResolverBenchmark.version N/A media true thrpt 10 98302.865 ± 4273.227 ops/s +1%
ArrayClassResolverBenchmark.version N/A media false thrpt 10 128159.221 ± 6510.381 ops/s -2%
FieldSerializerBenchmark.compatible true sample true thrpt 10 43527.254 ± 2327.122 ops/s
FieldSerializerBenchmark.compatible true sample false thrpt 10 46982.176 ± 2744.698 ops/s
FieldSerializerBenchmark.compatible true media true thrpt 10 31918.026 ± 2839.793 ops/s
FieldSerializerBenchmark.compatible true media false thrpt 10 37696.591 ± 3371.873 ops/s
FieldSerializerBenchmark.compatible false sample true thrpt 10 53078.727 ± 3879.036 ops/s
FieldSerializerBenchmark.compatible false sample false thrpt 10 58613.895 ± 7185.178 ops/s
FieldSerializerBenchmark.compatible false media true thrpt 10 54898.580 ± 8031.631 ops/s
FieldSerializerBenchmark.compatible false media false thrpt 10 60319.741 ± 4908.678 ops/s
FieldSerializerBenchmark.custom N/A sample true thrpt 10 189928.303 ± 9767.252 ops/s
FieldSerializerBenchmark.custom N/A sample false thrpt 10 264806.335 ± 17856.982 ops/s
FieldSerializerBenchmark.custom N/A media true thrpt 10 200178.669 ± 15657.228 ops/s
FieldSerializerBenchmark.custom N/A media false thrpt 10 278763.056 ± 23860.371 ops/s
FieldSerializerBenchmark.deserializeCollection N/A N/A N/A thrpt 10 2875.622 ± 207.313 ops/s
FieldSerializerBenchmark.field N/A sample true thrpt 10 129284.819 ± 7810.271 ops/s
FieldSerializerBenchmark.field N/A sample false thrpt 10 162516.436 ± 8409.000 ops/s
FieldSerializerBenchmark.field N/A media true thrpt 10 102061.165 ± 10577.557 ops/s
FieldSerializerBenchmark.field N/A media false thrpt 10 126808.879 ± 5899.001 ops/s
FieldSerializerBenchmark.tagged true sample true thrpt 10 63632.876 ± 3658.679 ops/s
FieldSerializerBenchmark.tagged true sample false thrpt 10 74430.252 ± 12033.111 ops/s
FieldSerializerBenchmark.tagged true media true thrpt 10 37004.967 ± 3504.114 ops/s
FieldSerializerBenchmark.tagged true media false thrpt 10 45238.982 ± 6951.446 ops/s
FieldSerializerBenchmark.tagged false sample true thrpt 10 116304.460 ± 8823.858 ops/s
FieldSerializerBenchmark.tagged false sample false thrpt 10 136836.705 ± 6600.080 ops/s
FieldSerializerBenchmark.tagged false media true thrpt 10 85643.895 ± 6990.174 ops/s
FieldSerializerBenchmark.tagged false media false thrpt 10 106480.011 ± 10509.133 ops/s
FieldSerializerBenchmark.version N/A sample true thrpt 10 132517.006 ± 17654.257 ops/s
FieldSerializerBenchmark.version N/A sample false thrpt 10 166078.647 ± 15443.341 ops/s
FieldSerializerBenchmark.version N/A media true thrpt 10 96624.854 ± 8067.814 ops/s
FieldSerializerBenchmark.version N/A media false thrpt 10 132029.226 ± 21952.161 ops/s
Process finished with exit code 0
The cache code of DefaultClassResolver don't work in ser/der of Map that has different classes for its key and value. You don't understand it maybe. It is important because huge objects are mainly collection.