Skip to content
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

Merged
merged 2 commits into from Sep 16, 2020

Conversation

r30shah
Copy link
Contributor

@r30shah r30shah commented Aug 11, 2020

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

@r30shah
Copy link
Contributor Author

r30shah commented Aug 11, 2020

@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;
}

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

@andrewcraik andrewcraik left a 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/codegen/J9RecognizedMethodsEnum.hpp Outdated Show resolved Hide resolved
@@ -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
Copy link
Contributor

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.

Copy link
Contributor Author

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

@andrewcraik andrewcraik self-assigned this Aug 11, 2020
@r30shah r30shah force-pushed the unsafePR branch 2 times, most recently from 5bba1b1 to cdb436c Compare August 12, 2020 00:31
@r30shah r30shah changed the title WIP: Recognize Unsafe.copyMemory0 in JDK11 Recognize Unsafe.copyMemory0 in JDK11 Aug 12, 2020
@@ -2212,6 +2212,23 @@ J9::Node::setDontInlinePutOrderedCall()
}

bool
J9::Node::isUnsafeCopyMemoryIntrinsic()
Copy link
Contributor Author

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.

@r30shah
Copy link
Contributor Author

r30shah commented Aug 12, 2020

@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

@andrewcraik
Copy link
Contributor

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:

=== Output from failing command(s) repeated here ===
* For target jdk__packages_attribute.done:
Exception in thread "main" java/lang/StackOverflowError
	at jdk/internal/misc/Unsafe.copyMemory (java.base@9/Unsafe.java:1293)

@r30shah Can you investigate please?

@r30shah
Copy link
Contributor Author

r30shah commented Aug 12, 2020

@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
Changes in this PR will skip wrapping up objects for JNI call jdk/internal/misc/Unsafe.copyMemory0 and that seems like causing the failure. Changes in eclipse/omr#5464 modifies the call to transformUnsafeCopyMemoryCall to return to false. So it won't break the build. May cause regression due to not doing transformation temporarily till this guy gets in. I am marking this WIP and removing WIP from the OMR

@r30shah r30shah changed the title Recognize Unsafe.copyMemory0 in JDK11 WIP: Recognize Unsafe.copyMemory0 in JDK11 Aug 12, 2020
@andrewcraik
Copy link
Contributor

Jenkins test sanity all jdk15 depends eclipse/omr#5464

@r30shah
Copy link
Contributor Author

r30shah commented Aug 17, 2020

Failure on Linux on Z seems like because of missing commits from OMR (eclipse/omr@7970637 , eclipse/omr@c84f6f9)
I will rebase the OMR once the build on other platforms gets finished,

@andrewcraik
Copy link
Contributor

@r30shah interesting 390 failure:

10:19:12  Assertion failed at /home/jenkins/workspace/Build_JDK15_s390x_linux_Personal/build/linux-s390x-server-release/vm/compiler/../omr/compiler/z/env/OMRCPU.cpp:117: self()->is_at_least_test(p)
10:19:12  VMState: 0x0005ff04
10:19:12  	processor Unknown(1) failed, _supportedArch z15(9), _processorDescription.processor z15(10)
10:19:12  compiling java/lang/System.getEncoding(I)Ljava/lang/String; at level: cold

doesn't look like your change, but something you or @fjeremic might be interested in.

@r30shah
Copy link
Contributor Author

r30shah commented Aug 17, 2020

@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/)
I am waiting for the last couple of ongoing builds finished before I re base both repo.
@fjeremic Do you think it is rebase issue or something more we need to check with the machine?

@r30shah r30shah force-pushed the unsafePR branch 3 times, most recently from ff0b1e1 to 5b7e35a Compare August 17, 2020 19:58
@r30shah
Copy link
Contributor Author

r30shah commented Aug 17, 2020

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?

runtime/compiler/il/J9Node.cpp Outdated Show resolved Hide resolved
runtime/compiler/il/J9Node.hpp Show resolved Hide resolved
@@ -11993,8 +11993,11 @@ J9::Power::CodeGenerator::inlineDirectCall(TR::Node *node, TR::Register *&result
}
break;
}

Copy link
Contributor

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.

@r30shah r30shah force-pushed the unsafePR branch 2 times, most recently from 91cf3d3 to fa538f2 Compare August 18, 2020 01:02
Comment on lines +287 to +290
/**
* Checks and return true if the callNode is JNI Call to Unsafe.copyMemory
*/
bool isUnsafeCopyMemoryIntrinsic();
Copy link
Contributor

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:

  1. 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))
  1. 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?

Copy link
Contributor Author

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.

Copy link
Contributor

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.

@r30shah
Copy link
Contributor Author

r30shah commented Aug 27, 2020

@andrewcraik Yes, WIP is for OMR dependency.

@andrewcraik
Copy link
Contributor

Jenkins test sanity all jdk15 depends eclipse/omr#5464

@andrewcraik
Copy link
Contributor

Jenkins test sanity all jdk15 depends eclipse/omr#5464

1 similar comment
@andrewcraik
Copy link
Contributor

Jenkins test sanity all jdk15 depends eclipse/omr#5464

@r30shah
Copy link
Contributor Author

r30shah commented Sep 3, 2020

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?

@andrewcraik
Copy link
Contributor

@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

@r30shah
Copy link
Contributor Author

r30shah commented Sep 8, 2020

@andrewcraik I agree, rebased the changes on both OMR and OpenJ9 repo.

@andrewcraik
Copy link
Contributor

Jenkins test sanity all jdk15 depends eclipse/omr#5464

@r30shah
Copy link
Contributor Author

r30shah commented Sep 8, 2020

Seems like couple of infrastructure failures in the test.

11:19:58  stderr: fatal: unable to access 'https://github.com/eclipse/openj9.git/': Failed to connect to github.com port 443: Connection timed out
11:19:58  
11:19:58  	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandIn(CliGitAPIImpl.java:2436)
11:19:58  	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.launchCommandWithCredentials(CliGitAPIImpl.java:2050)
11:19:58  	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl.access$500(CliGitAPIImpl.java:84)
11:19:58  	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl$1.execute(CliGitAPIImpl.java:572)
11:19:58  	at org.jenkinsci.plugins.gitclient.CliGitAPIImpl$2.execute(CliGitAPIImpl.java:801)
11:19:58  	at org.jenkinsci.plugins.gitclient.RemoteGitImpl$CommandInvocationHandler$GitCommandMasterToSlaveCallable.call(RemoteGitImpl.java:161)
11:19:58  	at org.jenkinsci.plugins.gitclient.RemoteGitImpl$CommandInvocationHandler$GitCommandMasterToSlaveCallable.call(RemoteGitImpl.java:154)
11:19:58  	at hudson.remoting.UserRequest.perform(UserRequest.java:211)
11:19:58  	at hudson.remoting.UserRequest.perform(UserRequest.java:54)
11:19:58  	at hudson.remoting.Request$2.run(Request.java:369)
11:19:58  	at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:72)
11:19:58  	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
11:19:58  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
11:19:58  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
11:19:58  	at java.lang.Thread.run(Thread.java:748)

@andrewcraik
Copy link
Contributor

Jenkins test sanity xlinux,xlinuxxl,zlinuxxl,plinux jdk15

@r30shah
Copy link
Contributor Author

r30shah commented Sep 9, 2020

@andrewcraik In the last launch build (#10366 (comment)) , OMR counterpart was not mentioned (eclipse/omr#5464) , hence we are seeing the stackoverflow errors.

@andrewcraik
Copy link
Contributor

sorry my bad - let's try again

@andrewcraik
Copy link
Contributor

Jenkins test sanity xlinux,xlinuxxl,zlinuxxl,plinux jdk15 depends eclipse/omr#5464

@andrewcraik
Copy link
Contributor

Jenkins test sanity all jdk15

@andrewcraik
Copy link
Contributor

Jenkins test sanity xlinux,xlinuxxl,zlinuxxl,plinux jdk15 depends eclipse/omr#5464

@r30shah
Copy link
Contributor Author

r30shah commented Sep 14, 2020

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.

@andrewcraik
Copy link
Contributor

Jenkins test sanity xlinux,xlinuxxl,zlinuxxl,plinux jdk15 depends eclipse/omr#5464

@r30shah
Copy link
Contributor Author

r30shah commented Sep 15, 2020

@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.

@r30shah r30shah changed the title WIP: Recognize Unsafe.copyMemory0 in JDK11 Recognize Unsafe.copyMemory0 in JDK11 Sep 16, 2020
@r30shah
Copy link
Contributor Author

r30shah commented Sep 16, 2020

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>
@andrewcraik
Copy link
Contributor

Previously passed all sanity and we need to get this in now to avoid seeing a perf regression so merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants