RFR: 8247532, 8248135: Records deserialization is slow + Build microbenchmarks with --enable-preview

David Holmes david.holmes at oracle.com
Wed Jun 24 06:03:04 UTC 2020


Hi Chris,

On 24/06/2020 2:30 am, Chris Hegarty wrote:
> 
>> On 23 Jun 2020, at 14:49, Peter Levart <peter.levart at gmail.com> wrote:
>>
>> ...
>>
>> Ok, I'm going to push this to jdk15.
> 
> Thank you Peter. This is a really nice change.
> 
> As a follow on, and not for JDK 15, I observe that Class::isRecord0 / JVM_IsRecord shows up as consuming a significant amount of time, more than 10%, in some runs of the deserialization benchmark. The isRecord implementation is a native method in the JVM, so relatively expensive to call.
> 
> This shows an opportunity to improve the Class::isRecord implementation with a simple cache of the record-ness of the j.l.Class, as is done selectively with other particular aspects of a class’s state. There are various ways to implement this, but here is just one [*].

There has been reluctance to add more and more fields to Class to cache 
all these new attributes that are being added - but ultimately that is a 
call for core-libs folk to make. The general expectation is/was that the 
need to ask a class if it is a Record (or isSealed etc) would be rare. 
But (de)serialization is the exception for isRecord() as unlike enums a 
simple instanceof test can't be used.

Cheers,
David
-----

> Running the deserialization benchmark with this change [*], gives the following results:
> 
> Benchmark                                    (length)  Mode  Cnt    Score    Error  Units
> RecordSerializationBench.deserializeClasses        10  avgt   10   14.136 ±  0.841  us/op
> RecordSerializationBench.deserializeClasses       100  avgt   10   61.821 ±  1.279  us/op
> RecordSerializationBench.deserializeClasses      1000  avgt   10  519.473 ±  7.950  us/op
> RecordSerializationBench.deserializeRecords        10  avgt   10   13.781 ±  1.917  us/op
> RecordSerializationBench.deserializeRecords       100  avgt   10   54.061 ±  4.188  us/op
> RecordSerializationBench.deserializeRecords      1000  avgt   10  444.538 ± 13.940  us/op
> 
> I think it is worth considering caching the record-ness state of a j.l.Class, as I’m sure it will be widely used in third-party serialization libraries, as well as by Java Serialization.
> 
> -Chris.
> 
> [*]
> diff -r 3a9521647349 src/java.base/share/classes/java/lang/Class.java
> --- a/src/java.base/share/classes/java/lang/Class.java	Tue Jun 23 10:46:39 2020 +0100
> +++ b/src/java.base/share/classes/java/lang/Class.java	Tue Jun 23 17:11:35 2020 +0100
> @@ -3712,9 +3712,17 @@
>       @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
>                                    essentialAPI=false)
>       public boolean isRecord() {
> -        return getSuperclass() == JAVA_LANG_RECORD_CLASS && isRecord0();
> +        if (!isRecordCalled) {
> +            isRecord = getSuperclass() == JAVA_LANG_RECORD_CLASS && isRecord0();
> +            isRecordCalled = true;
> +        }
> +        return isRecord;
>       }
>   
> +    // cached record(ness) status
> +    private transient boolean isRecord;
> +    private transient boolean isRecordCalled;
> +
>       // Fetches the factory for reflective objects
>       private static ReflectionFactory getReflectionFactory() {
>           if (reflectionFactory == null) {
> 


More information about the core-libs-dev mailing list