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
Recognize Unsafe.copyMemory0 in JDK11 #10366
Conversation
@andrewcraik Can I please get this one reviewed, I am currently performing the sanity tests on the changes so marking it WIP. |
@@ -11993,8 +11993,11 @@ J9::Power::CodeGenerator::inlineDirectCall(TR::Node *node, TR::Register *&result | |||
} | |||
break; | |||
} | |||
|
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.
I have a question to both @gita-omr and @andrewcraik , I see that P and x86 codegen further forces the Unsafe.copyMemory calls to be inlined in case optimizer misses it. I do not see we do it on Z. Is it possible (Apart from running with noOpt) that optimizer would miss this call to transform?
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.
the inlining in the inliner is always optional - the inliner may run out of budget before considering a call or may choose to spend budget elsewhere. While things like always inline bypass most of the heuristics related to budget - the current inliner is eager and so once it has consumed its budget it will stop considering callsites which can leave 'alwaysInline' methods not inlined.
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.
IMO we should move that reduction out of the codegen evaluators and right into the J9RecognizedCallTransformer so all codegens can transparently take advantage. I'd try to avoid duplicating the already duplicated logic on Z.
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.
Overall I do not like the Java version checks - we have avoided those to make it easier to test the JIT since all code runs all the time. I would rather we look at reworking this to better match how other multi-implementation methods have been handled with less macros.
runtime/compiler/il/J9Node.cpp
Outdated
@@ -299,7 +299,12 @@ J9::Node::processJNICall(TR::TreeTop * callNodeTreeTop, TR::ResolvedMethodSymbol | |||
#endif | |||
|
|||
if (comp->canTransformUnsafeCopyToArrayCopy() && | |||
(methodSymbol->getRecognizedMethod() == TR::sun_misc_Unsafe_copyMemory)) | |||
#if JAVA_SPEC_VERSION == 8 |
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.
I really don't think the method specific naming convention here makes sense. I think we should have an Unsafe_copyMemory_intrinsic which is what we match the sun/misc/Unsafe.copyMemory to under JDK8 and what we match the copyMemory0 to under JDK11. I think also that if there is a method to be inlined like jdk_internal_misc_Unsafe_copyMmeory0 that recognition can be matched unconditionally - it will only match when we are running JDK11 onward when the method moved. If there is a windows where the method moved but was native we can just check for the method being native before we recognize it and make all that matching code uncondition.
Using the Unsafe_copyMemory_intrinsic that is what OMR can reference and avoid Java specific issues to surface at that level of the architecture.
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.
@andrewcraik I have made changes that removes the #if macros that was checking the JAVA Version. I agree that we do not have to guard jdk_internal_misc_Unsafe_copyMmeory0
with JAVA SPEC version. Right now in JDK8 and JDK11, we have seen JNI methods sun/misc/Unsafe.copyMemory and jdk/internal/misc/Unsafe.copyMemory0 respectively and I have added an additional check to make sure it does the transformation only when it is JNI method in d1952e6
5bba1b1
to
cdb436c
Compare
@@ -2212,6 +2212,23 @@ J9::Node::setDontInlinePutOrderedCall() | |||
} | |||
|
|||
bool | |||
J9::Node::isUnsafeCopyMemoryIntrinsic() |
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.
I found that having a query on the call node is the most convenient place as we can have all the information to check whether call node is JNI call and it is one of the recognized copyMemory method.
@andrewcraik My functional testing has finished and I have also tried to address the comments. This one is good for review. Also this change is dependant on OMR counterpart eclipse/omr#5464 |
is this change dependent on the omr? We do want to remove the OMR function but can do so once it has been added in the OpenJ9 layer - there shouldn't be a conflict. Looks like there was some kind of functional problem in the Travis build:
@r30shah Can you investigate please? |
@andrewcraik We can not let this guy go first before the OMR one is merged. The failure happening in the travis build is because of this https://github.com/eclipse/openj9/blob/7ff0542881fc7b7b3e82f96b7358c10729c9fb53/runtime/compiler/il/J9Node.cpp#L385-L415 |
Jenkins test sanity all jdk15 depends eclipse/omr#5464 |
Failure on Linux on Z seems like because of missing commits from OMR (eclipse/omr@7970637 , eclipse/omr@c84f6f9) |
@r30shah interesting 390 failure:
doesn't look like your change, but something you or @fjeremic might be interested in. |
@andrewcraik , Yes failures are not related to this changes, either I need to rebase the repo or something with the z15 machine on which this build was ran (https://ci.eclipse.org/openj9/computer/rh7-390-2/) |
ff0b1e1
to
5b7e35a
Compare
I have rebased the changes with latest master on both OpenJ9 and OMR, if changes are OK, can we get the builds on s390 linux? |
@@ -11993,8 +11993,11 @@ J9::Power::CodeGenerator::inlineDirectCall(TR::Node *node, TR::Register *&result | |||
} | |||
break; | |||
} | |||
|
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.
IMO we should move that reduction out of the codegen evaluators and right into the J9RecognizedCallTransformer so all codegens can transparently take advantage. I'd try to avoid duplicating the already duplicated logic on Z.
91cf3d3
to
fa538f2
Compare
/** | ||
* Checks and return true if the callNode is JNI Call to Unsafe.copyMemory | ||
*/ | ||
bool isUnsafeCopyMemoryIntrinsic(); |
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.
This API seems very very specific for it to exist in the Node
class. I worry this class will turn into a kitchen sink eventually. Does this really need to exist? It seems it gets used in two locations:
- In
processJNICall
which we can just replace with:
if (comp->canTransformUnsafeCopyToArrayCopy() &&
(methodSymbol->getRecognizedMethod() == TR::sun_misc_Unsafe_copyMemory ||
methodSymbol->getRecognizedMethod() == TR::jdk_internal_misc_Unsafe_copyMemory0))
- In
transformUnsafeCopyMemoryCall
which we can just inline a partial version of this API.
Are we sure introducing this extra complexity into the Node
class outweighs the benefits?
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.
@fjeremic Reason I chose to introduce this API in Node class is that it contains all the information that it needed to verify if the JNI call can be transformed. Idea behind using this intrinsic is that if in later version of JDK if there are changes in the call chain, we only need to make changes in one place.
There is another potential use of this API in recognized call transformer to identify and transform this call as you suggested in #10366 (comment) , which I think we should pursue and remove the complexity and duplicate code from the codegen.
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.
That sounds reasonable. Thanks for explaining further uses.
@andrewcraik Yes, WIP is for OMR dependency. |
Jenkins test sanity all jdk15 depends eclipse/omr#5464 |
Jenkins test sanity all jdk15 depends eclipse/omr#5464 |
1 similar comment
Jenkins test sanity all jdk15 depends eclipse/omr#5464 |
Seems like some this one also needs a rebase, @andrewcraik Do you want me to wait for rest of the tests to finish and then rebase or rebase it and you can launch the test again? |
@r30shah if you can rebase I'll just rerun the testing - I want to be sure things are good before we start the merge sequence since there will be a perf regression if we don't merge this one quickly enough |
@andrewcraik I agree, rebased the changes on both OMR and OpenJ9 repo. |
Jenkins test sanity all jdk15 depends eclipse/omr#5464 |
Seems like couple of infrastructure failures in the test.
|
Jenkins test sanity xlinux,xlinuxxl,zlinuxxl,plinux jdk15 |
@andrewcraik In the last launch build (#10366 (comment)) , OMR counterpart was not mentioned (eclipse/omr#5464) , hence we are seeing the stackoverflow errors. |
sorry my bad - let's try again |
Jenkins test sanity xlinux,xlinuxxl,zlinuxxl,plinux jdk15 depends eclipse/omr#5464 |
Jenkins test sanity all jdk15 |
Jenkins test sanity xlinux,xlinuxxl,zlinuxxl,plinux jdk15 depends eclipse/omr#5464 |
Not sure what is happening, but failing builds have not picked up the eclipse/omr#5464. In the passed builds, I do not see on console log it explicitly checks out the changes from the OMR Counterpart. |
Jenkins test sanity xlinux,xlinuxxl,zlinuxxl,plinux jdk15 depends eclipse/omr#5464 |
@andrewcraik I see all the platform on which this tests were launched in #10366 (comment) are passed. Not sure why I am seeing mac and windows. But this one is good to merge IMO. If you are OK with it, we need to first let OMR changes in then OpenJ9. |
Change in eclipse/omr#5464 has been merged yesterday and passed OMR acceptance, this one is good to go, removing WIP |
OpenJ9 contains the optimization that recognizes the JNI call sun/misc/Unsafe.copyMemory and transforms it to System.arrayCopy calls, which is inlined and optimized on most of the platform. Due to implementation changes in JDK11 we can not apply this optimization to sun/misc/Unsafe.copyMemory method which in Java 11 acts as a java wrapper that calls the implementation of copyMemory method from jdk/internal/misc/Unsafe class. This implementation contains additional changes to check range for the source and destination (in case of illegal access throws RuntimeException) before calling the actual JNI method jdk/internal/misc/Unsafe.copyMemory0 which can be transformed to System.arrayCopy call. Due to this behavioural changes, when compiling method that calls Unsafe.copyMemory, we need to make sure that optimizer is exposed to JNI call Unsafe.copyMemory0 and that call is recognized same way as JNI call sun/misc/Unsafe.copyMemory is recognized in Java 8 to optimize it further. Signed-off-by: Rahil Shah <rahil@ca.ibm.com>
Transformation from Unsafe.copyMemory to System.arrayCopy was Java specific transformation. This commit moves the transformation to OpenJ9. Signed-off-by: Rahil Shah <rahil@ca.ibm.com>
Previously passed all sanity and we need to get this in now to avoid seeing a perf regression so merging. |
OpenJ9 contains the optimization that recognizes the JNI call sun/misc/Unsafe.copyMemory and transforms it to System.arrayCopy calls, which is inlined and optimized on most of the platform. Due to implementation changes in JDK11 we can not apply this optimization to sun/misc/Unsafe.copyMemory method which in Java 11 acts as a java wrapper that calls the implementation of copyMemory method from jdk/internal/misc/Unsafe class. This implementation contains additional changes to check range for the source and destination (in case of illegal access throws RuntimeException) before calling the
actual JNI method jdk/internal/misc/Unsafe.copyMemory0 which can be transformed to System.arrayCopy call. Due to this behavioural changes, when compiling method that calls Unsafe.copyMemory, we need to make sure that optimizer is exposed to JNI call Unsafe.copyMemory0 and that call is recognized same way as JNI call sun/misc/Unsafe.copyMemory is recognized in Java 8 to optimize it further.
Signed-off-by: Rahil Shah rahil@ca.ibm.com