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
8259065: Optimize MessageDigest.getInstance #1933
Conversation
👋 Welcome back redestad! A progress list of the required criteria for merging this PR into |
Webrevs
|
…x inefficient synchronization in ProviderConfig. Store EngineDescriptor in Service instead of looking it up every time.
I refactored and optimized the lookup code further, getting rid of a number of bottlenecks:
|
Since much of the cost is now the creation of the MessageDigest itself, I added a microbenchmark to stat this overhead:
That means there's no added allocation overhead of calling |
Nice speedup for all |
Thanks for looking into this. I will take a look. |
|
||
return md; | ||
GetInstance.Instance instance = GetInstance.getInstance("MessageDigest", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is another Security.getImpl call inside getInstance(String algorithm, String provider) method. For consistency sake, we should update it also?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, why not. The Security.getImpl has a branch checking null provider which is pointless here since we guard against a null provider before that call, so we can reuse the same pattern here.
@@ -1106,16 +1069,15 @@ private ServiceKey(String type, String algorithm, boolean intern) { | |||
this.algorithm = intern ? algorithm.intern() : algorithm; | |||
} | |||
public int hashCode() { | |||
return Objects.hash(type, algorithm); | |||
return type.hashCode() ^ algorithm.hashCode(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this change really necessary? It's faster to compute with ^, but does the generated hash values are as distinct as using Objects.hash()?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid any suspicion we'd generate a worse hash here I've reverted this to inline what would be generated going through Objects.hash: 31*31 + type.hashCode()*31 + algorithm.hashCode()
} | ||
Class<?> clazz = null; | ||
if (cache instanceof WeakReference<?> ref){ | ||
clazz = (ref == null) ? null : (Class<?>)ref.get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ref should not be null if the instanceof check is true?
} | ||
Constructor<?> con = null; | ||
if (cache instanceof WeakReference<?> ref){ | ||
con = (ref == null) ? null : (Constructor<?>)ref.get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ref should not be null if the instanceof check is true?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catches - these 2 null checks can be removed
src/java.base/share/classes/sun/security/jca/ProviderConfig.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reviewing, Valerie. I've addressed all your comments.
|
||
return md; | ||
GetInstance.Instance instance = GetInstance.getInstance("MessageDigest", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, why not. The Security.getImpl has a branch checking null provider which is pointless here since we guard against a null provider before that call, so we can reuse the same pattern here.
@@ -1106,16 +1069,15 @@ private ServiceKey(String type, String algorithm, boolean intern) { | |||
this.algorithm = intern ? algorithm.intern() : algorithm; | |||
} | |||
public int hashCode() { | |||
return Objects.hash(type, algorithm); | |||
return type.hashCode() ^ algorithm.hashCode(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid any suspicion we'd generate a worse hash here I've reverted this to inline what would be generated going through Objects.hash: 31*31 + type.hashCode()*31 + algorithm.hashCode()
} | ||
Constructor<?> con = null; | ||
if (cache instanceof WeakReference<?> ref){ | ||
con = (ref == null) ? null : (Constructor<?>)ref.get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catches - these 2 null checks can be removed
src/java.base/share/classes/sun/security/jca/ProviderConfig.java
Outdated
Show resolved
Hide resolved
@cl4es This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 64 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
Thanks for reviewing, Valerie! /integrate |
@cl4es Since your change was applied there have been 65 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit fc1d2a1. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
By caching default constructors used in
java.security.Provider::newInstanceUtil
in aClassValue
, we can reduce the overhead of allocating instances in a variety of places, e.g.,MessageDigest::getInstance
, without compromising thread-safety or security.On the provided microbenchmark
MessageDigest.getInstance(digesterName)
improves substantially for anydigesterName
- around -90ns/op and -120B/op:Patch:
See: https://cl4es.github.io/2021/01/04/Investigating-MD5-Overheads.html#reflection-overheads for context.
Progress
Issue
Reviewers
Download
$ git fetch https://git.openjdk.java.net/jdk pull/1933/head:pull/1933
$ git checkout pull/1933