RFR: 8247532: Records deserialization is slow

Peter Levart peter.levart at gmail.com
Sun Jun 14 16:28:21 UTC 2020


Hi,


I noticed that deserializing records (new preview Java feature in JDK14 
and JDK15) is slow compared to equivalent classical classes. I created a 
JMH benchmark [1] to se how it compares (ran it on JDK14):


Benchmark                                                                     Mode  Cnt       Score        Error   Units
RecordSerializationBench.deserializeClasses                                   avgt   10      31.911 ±      0.218   us/op
RecordSerializationBench.deserializeClasses:·gc.alloc.rate                    avgt   10     815.106 ±      5.545  MB/sec
RecordSerializationBench.deserializeClasses:·gc.alloc.rate.norm               avgt   10   40921.903 ±      0.615    B/op
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Eden_Space           avgt   10     839.522 ±    191.195  MB/sec
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Eden_Space.norm      avgt   10   42153.661 ±   9682.799    B/op
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Survivor_Space       avgt   10       0.117 ±      0.492  MB/sec
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Survivor_Space.norm  avgt   10       5.835 ±     24.447    B/op
RecordSerializationBench.deserializeClasses:·gc.count                         avgt   10      21.000               counts
RecordSerializationBench.deserializeClasses:·gc.time                          avgt   10      17.000                   ms
RecordSerializationBench.deserializeRecords                                   avgt   10     531.333 ±      3.094   us/op
RecordSerializationBench.deserializeRecords:·gc.alloc.rate                    avgt   10     346.511 ±      1.997  MB/sec
RecordSerializationBench.deserializeRecords:·gc.alloc.rate.norm               avgt   10  289637.193 ±      6.894    B/op
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Eden_Space           avgt   10     359.773 ±    191.116  MB/sec
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Eden_Space.norm      avgt   10  300657.838 ± 159724.346    B/op
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Survivor_Space       avgt   10       0.007 ±      0.012  MB/sec
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Survivor_Space.norm  avgt   10       6.020 ±      9.910    B/op
RecordSerializationBench.deserializeRecords:·gc.count                         avgt   10       9.000               counts
RecordSerializationBench.deserializeRecords:·gc.time                          avgt   10      14.000                   ms


...not only it is it about 16x slower, it also produces 7x garbage. I 
checked the code and it is not very optimal. It matches the record 
component names with object stream fields in O(n^2) way. It uses method 
handles but binds arguments of canonical constructor each time an 
instance of record is constructed. So I tried to optimize it [2] and 
with that patch on top of JDK16 the benchmark produces the following 
results:


Benchmark                                                                     Mode  Cnt      Score       Error   Units
RecordSerializationBench.deserializeClasses                                   avgt   10     31.049 ±     0.235   us/op
RecordSerializationBench.deserializeClasses:·gc.alloc.rate                    avgt   10    837.614 ±     6.326  MB/sec
RecordSerializationBench.deserializeClasses:·gc.alloc.rate.norm               avgt   10  40921.931 ±     0.666    B/op
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Eden_Space           avgt   10    867.743 ±   251.373  MB/sec
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Eden_Space.norm      avgt   10  42405.532 ± 12403.301    B/op
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Survivor_Space       avgt   10      0.126 ±     0.478  MB/sec
RecordSerializationBench.deserializeClasses:·gc.churn.G1_Survivor_Space.norm  avgt   10      6.113 ±    23.268    B/op
RecordSerializationBench.deserializeClasses:·gc.count                         avgt   10     22.000              counts
RecordSerializationBench.deserializeClasses:·gc.time                          avgt   10     19.000                  ms
RecordSerializationBench.deserializeRecords                                   avgt   10     33.588 ±     0.394   us/op
RecordSerializationBench.deserializeRecords:·gc.alloc.rate                    avgt   10    500.033 ±     5.871  MB/sec
RecordSerializationBench.deserializeRecords:·gc.alloc.rate.norm               avgt   10  26425.293 ±     0.759    B/op
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Eden_Space           avgt   10    512.772 ±   288.112  MB/sec
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Eden_Space.norm      avgt   10  27090.499 ± 15175.280    B/op
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Survivor_Space       avgt   10      0.134 ±     0.496  MB/sec
RecordSerializationBench.deserializeRecords:·gc.churn.G1_Survivor_Space.norm  avgt   10      7.128 ±    26.526    B/op
RecordSerializationBench.deserializeRecords:·gc.count                         avgt   10     13.000              counts
RecordSerializationBench.deserializeRecords:·gc.time                          avgt   10     17.000                  ms


...so here the speed is comparable and it even produces less garbage.


I created an issue [3].

So WDYT? Since this is still a preview feature in JDK15, is it possible 
to squeeze it into JDK15?

Regards, Peter


[1] 
http://cr.openjdk.java.net/~plevart/jdk-dev/RecordsDeserialization/RecordSerializationBench.java

[2] 
http://cr.openjdk.java.net/~plevart/jdk-dev/RecordsDeserialization/webrev.01/

[3] https://bugs.openjdk.java.net/browse/JDK-8247532





More information about the core-libs-dev mailing list