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



Reply via email to