Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ArrayClassResolver #878

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open

Conversation

lifeinwild
Copy link

  • 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.

This modification provides a faster lookup from classID to Registration.
A fix because an error occured after checkout latest remote version. And by changing Sample to String in the value of Map, the performance difference of ClassResolver is more clear in the score.
@lifeinwild
Copy link
Author

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.

@theigl
Copy link
Collaborator

theigl commented Jan 26, 2022

@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?

@lifeinwild
Copy link
Author

lifeinwild commented Jan 26, 2022

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.

@lifeinwild
Copy link
Author

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.

@lifeinwild
Copy link
Author

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

@lifeinwild
Copy link
Author

lifeinwild commented Jan 27, 2022

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.

@lifeinwild
Copy link
Author

lifeinwild commented Jan 30, 2022

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

@lifeinwild
Copy link
Author

lifeinwild commented Mar 18, 2022

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

2 participants