RFR: 8259065: Optimize MessageDigest.getInstance

David Schlosnagle github.com+54594+schlosna at openjdk.java.net
Wed Jan 6 02:33:53 UTC 2021


On Wed, 6 Jan 2021 01:20:40 GMT, Claes Redestad <redestad at openjdk.org> wrote:

>> I refactored and optimized the lookup code further, getting rid of a number of bottlenecks:
>> 
>> - Cache Constructors in Provider.Service instead of via a ClassValue.
>> - Also cache the impl Class, wrap Class and Constructor in WeakReference if not loaded by the null classloader (many builtins will be)
>> - Cache EngineDescription in Service, avoiding a lookup on the hot path
>> - We were hitting a synchronized method in ProviderConfig.getProvider(). The provider field is volatile already, so I used the double-check idiom here to avoid synchronization on the hot path
>> - ServiceKey.hashCode using Objects.hash was cause for allocation, simplified and optimized it.
>> 
>> Benchmark                                                      (digesterName)  Mode  Cnt     Score    Error   Units
>> GetMessageDigest.getInstance                                              MD5  avgt   30   143.803 ±  5.431   ns/op
>> GetMessageDigest.getInstance:·gc.alloc.rate.norm                          MD5  avgt   30   280.015 ±  0.001    B/op
>
> Since much of the cost is now the creation of the MessageDigest itself, I added a microbenchmark to stat this overhead:
> 
> Benchmark                                                        (digesterName)  Mode  Cnt     Score     Error   Units
> GetMessageDigest.cloneInstance                                              MD5  avgt   30   124.922 ±   5.412   ns/op
> GetMessageDigest.cloneInstance:·gc.alloc.rate.norm                          MD5  avgt   30   280.015 ±   0.001    B/op
> 
> That means there's no added allocation overhead of calling `MessageDigest.getInstance(digesterName)` compared to cloning an existing instance - which means we get almost all of the benefits without resorting to tricks as caching and cloning an instance at call sites such as the one in `UUID::nameUUIDFromBytes`. The remaining 20ns/op difference should be negligible.

Nice speedup for all `MessageDigest.getInstance` and `Provider.getService` invocations and improves on removing the scalability bottlenecks of `Provider.getService` beyond [JDK-7092821](https://bugs.openjdk.java.net/browse/JDK-7092821) (and related [JDK-8080273](https://bugs.openjdk.java.net/browse/JDK-8080273) & [JDK-8172827](https://bugs.openjdk.java.net/browse/JDK-8172827)). This will also allow removing some longstanding `MessageDigest#clone` workarounds such as in Guava https://github.com/google/guava/issues/1197 .

-------------

PR: https://git.openjdk.java.net/jdk/pull/1933



More information about the security-dev mailing list