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

[WIP][SPARK-26896] JDK 11 module adjustments for running tests #23804

Closed
wants to merge 1 commit into from

Conversation

squito
Copy link
Contributor

@squito squito commented Feb 15, 2019

This adds a JDK11 profile, just intended for running tests. It adds
extra runtime arguments to the test runners to get around new module
limitations. This includes:

  1. removal of jaxb from java itself (used in pmml export in mllib)

  2. Some reflective access which results in failures, eg.

Unable to make field jdk.internal.ref.PhantomCleanable
jdk.internal.ref.PhantomCleanable.prev accessible: module java.base does
not "opens jdk.internal.ref" to unnamed module

  1. Some reflective access which results in warnings.

This adds a JDK11 profile, just intended for running tests.  It adds
extra runtime arguments to the test runners to get around new module
limitations.  This includes:

1) removal of jaxb from java itself (used in pmml export in mllib)

2) Some reflective access which results in failures, eg.

Unable to make field jdk.internal.ref.PhantomCleanable
jdk.internal.ref.PhantomCleanable.prev accessible: module java.base does
not "opens jdk.internal.ref" to unnamed module

3) Some reflective access which results in warnings.
@squito
Copy link
Contributor Author

squito commented Feb 15, 2019

I have NOT fully tested this on jdk11. This is based on a similar patch I'm doing on a fork. I am just sharing it to help anybody else along / start discussion.

@SparkQA
Copy link

SparkQA commented Feb 16, 2019

Test build #102404 has finished for PR 23804 at commit 16caf67.

  • This patch passes all tests.
  • This patch merges cleanly.
  • This patch adds no public classes.

@@ -2117,7 +2119,7 @@
<include>**/*Suite.java</include>
</includes>
<reportsDirectory>${project.build.directory}/surefire-reports</reportsDirectory>
<argLine>-ea -Xmx4g -Xss4m -XX:ReservedCodeCacheSize=${CodeCacheSize}</argLine>
<argLine>-ea -Xmx3g -Xss4m -XX:ReservedCodeCacheSize=${CodeCacheSize} ${jdk11.module.args}</argLine>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, @squito . Do we need to reduce this back to 3g for JDK11?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh no, sorry that was not supposed to be part of this change, sorry.

@srowen
Copy link
Member

srowen commented Feb 18, 2019

I'm unclear why these would only be applicable to test scope?
Is it a problem to just specify a JAXB dependency everywhere rather than make a profile?

I think we can't work around this by adding a bunch of command line args. Users can't be expected to do this. But I think you're saying it only affects tests. What was the source of the failure? there may be other answers.

@squito
Copy link
Contributor Author

squito commented Feb 19, 2019

I'm unclear why these would only be applicable to test scope?
Is it a problem to just specify a JAXB dependency everywhere rather than make a profile?

I think we can't work around this by adding a bunch of command line args. Users can't be expected to do this. But I think you're saying it only affects tests. What was the source of the failure? there may be other answers.

Yeah, all good questions -- honestly I don't know the answers either, I am not sure this is the right final change, but I thought it might be useful to share as others will hit the same issues.

Maybe it is just fine to just add jaxb, even though it'll already be present in jdk8? I'm not sure.

The add-opens part is much trickier to deal with though. Sure, it would be great to not require the profile & args etc. But you can't pass those args in to java 8, it'll fail immediately because of the unrecognized option. We could change spark code to stop using those internal modules, though that seems like it might be a big task. Or we could try to make spark-submit automatically add those arguments, so users dont' have to worry about them. But we'd still need the maven profile. (though it might be possible to make this maven profile automatically activated if you're using java11, and not require any extra flags.)

Regardless, a change like this might be a step forward to get more people building and testing with jdk11?

@srowen
Copy link
Member

srowen commented Feb 19, 2019

It's probably better in the end to have an explicit JAXB dependency even in Java 8. But IIRC the tests were passing for Java 11, or at least, I don't recall any JAXB issues.

What fails if you don't add the add-opens flags? Certainly the use of Unsafe did but we worked around that.

That is ... I thought this was all already 99% working :) what are you seeing?

@squito
Copy link
Contributor Author

squito commented Feb 19, 2019

I thought you only ran tests on core? I think all the issues I ran into were in other packages. Sorry my notes are a bit scattered -- most of this is from mllib stuff. Some tests failed with a stack trace pointing to a model.transform() call, but with an exception like

Unable to make field jdk.internal.ref.PhantomCleanable
jdk.internal.ref.PhantomCleanable.prev accessible: module java.base does
not "opens jdk.internal.ref" to unnamed module

The bigger issue I ran into, actually, is SPARK-26839, which caused problems with unit tests in the hive module. I haven't posted the changes I've made yet, because I know what I've done is different in my fork. But if you've run hive tests successfully with jdk11 -- maybe that means I'm doing something else wrong in my setup?

@srowen
Copy link
Member

srowen commented Feb 19, 2019

I see, could be, yeah. I don't see where we try to touch PhantomCleanable or prev though; do you have any more context on the failure? ideally we'd work around it or stop using some hack if isn't buying much.

@squito
Copy link
Contributor Author

squito commented Feb 19, 2019

yeah I didn't understand it either. The stack trace really didn't make sense to me, but I found putting in the add-opens rule made it go away. Later on in my jdk 11 experiments, I discovered that somehow maven / surefire were doing some funny class-loading which was obscuring stack traces -- I was able to get a full and meaningful traces by directly invoking junit. I should probably try that again on the failures that I hit

(sorry this has only partial attention from me at the moment -- like I said, just wanted to post for discussion as I'm sure others are experimenting with jdk11 ...)

@srowen
Copy link
Member

srowen commented Feb 21, 2019

Oh I see it now:

[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.935 s <<< FAILURE! - in org.apache.spark.ml.regression.JavaGBTRegressorSuite
[ERROR] runDT(org.apache.spark.ml.regression.JavaGBTRegressorSuite)  Time elapsed: 0.933 s  <<< ERROR!
java.lang.reflect.InaccessibleObjectException: Unable to make field jdk.internal.ref.PhantomCleanable jdk.internal.ref.PhantomCleanable.prev accessible: module java.base does not "opens jdk.internal.ref" to unnamed module @4212a0c8
	at org.apache.spark.ml.regression.JavaGBTRegressorSuite.runDT(JavaGBTRegressorSuite.java:65)

[INFO] Running org.apache.spark.ml.regression.JavaDecisionTreeRegressorSuite
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.43 s - in org.apache.spark.ml.regression.JavaDecisionTreeRegressorSuite
[INFO] Running org.apache.spark.ml.regression.JavaRandomForestRegressorSuite
[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.507 s <<< FAILURE! - in org.apache.spark.ml.regression.JavaRandomForestRegressorSuite
[ERROR] runDT(org.apache.spark.ml.regression.JavaRandomForestRegressorSuite)  Time elapsed: 0.506 s  <<< ERROR!
java.lang.reflect.InaccessibleObjectException: Unable to make field jdk.internal.ref.PhantomCleanable jdk.internal.ref.PhantomCleanable.prev accessible: module java.base does not "opens jdk.internal.ref" to unnamed module @4212a0c8
	at org.apache.spark.ml.regression.JavaRandomForestRegressorSuite.runDT(JavaRandomForestRegressorSuite.java:88)

I can investigate too.

@srowen
Copy link
Member

srowen commented Feb 21, 2019

I got the stack trace:

        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:337)
        at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:281)
        at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:176)
        at java.base/java.lang.reflect.Field.setAccessible(Field.java:170)
        at org.apache.spark.util.SizeEstimator$.$anonfun$getClassInfo$2(SizeEstimator.scala:337)
        at org.apache.spark.util.SizeEstimator$.$anonfun$getClassInfo$2$adapted(SizeEstimator.scala:331)
        at scala.collection.IndexedSeqOptimized.foreach(IndexedSeqOptimized.scala:36)
        at scala.collection.IndexedSeqOptimized.foreach$(IndexedSeqOptimized.scala:33)
        at scala.collection.mutable.ArrayOps$ofRef.foreach(ArrayOps.scala:198)
        at org.apache.spark.util.SizeEstimator$.getClassInfo(SizeEstimator.scala:331)
        at org.apache.spark.util.SizeEstimator$.getClassInfo(SizeEstimator.scala:325)
        at org.apache.spark.util.SizeEstimator$.visitSingleObject(SizeEstimator.scala:223)
        at org.apache.spark.util.SizeEstimator$.estimate(SizeEstimator.scala:202)
        at org.apache.spark.util.SizeEstimator$.estimate(SizeEstimator.scala:70)
        at org.apache.spark.util.collection.SizeTracker.takeSample(SizeTracker.scala:78)
        at org.apache.spark.util.collection.SizeTracker.afterUpdate(SizeTracker.scala:70)
        at org.apache.spark.util.collection.SizeTracker.afterUpdate$(SizeTracker.scala:67)
        at org.apache.spark.util.collection.SizeTrackingVector.$plus$eq(SizeTrackingVector.scala:31)
        at org.apache.spark.storage.memory.DeserializedValuesHolder.storeValue(MemoryStore.scala:665)
        at org.apache.spark.storage.memory.MemoryStore.putIterator(MemoryStore.scala:222)
        at org.apache.spark.storage.memory.MemoryStore.putIteratorAsValues(MemoryStore.scala:299)
        at org.apache.spark.storage.BlockManager.$anonfun$doPutIterator$1(BlockManager.scala:1166)
        at org.apache.spark.storage.BlockManager.doPut(BlockManager.scala:1092)
        at org.apache.spark.storage.BlockManager.doPutIterator(BlockManager.scala:1157)
        at org.apache.spark.storage.BlockManager.putIterator(BlockManager.scala:915)
        at org.apache.spark.storage.BlockManager.putSingle(BlockManager.scala:1482)
        at org.apache.spark.broadcast.TorrentBroadcast.writeBlocks(TorrentBroadcast.scala:133)
        at org.apache.spark.broadcast.TorrentBroadcast.<init>(TorrentBroadcast.scala:91)
        at org.apache.spark.broadcast.TorrentBroadcastFactory.newBroadcast(TorrentBroadcastFactory.scala:34)
        at org.apache.spark.broadcast.BroadcastManager.newBroadcast(BroadcastManager.scala:62)
        at org.apache.spark.SparkContext.broadcast(SparkContext.scala:1427)
        at org.apache.spark.ml.regression.GBTRegressionModel.transformImpl(GBTRegressor.scala:249)

The trick is to disable the JVM optimization that removes stack traces, with -XX:-OmitStackTraceInFastThrow

OK, it's because SizeEstimator is trying to make this thing accessible to estimate size. We may need to ignore fields that can't be made accessible or at least blacklist fields like this.

@srowen
Copy link
Member

srowen commented Feb 22, 2019

OK, this fixes this particular error: #23866

The JAXB thing relates to JPMML. I think my first attempt to fix that will be update JPMML, which seems to need an update for Java 9 anyway. I think it's specifying the Sun implementation somewhere:

- pmml export *** FAILED ***
  javax.xml.bind.JAXBException:
  at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:207)
  at javax.xml.bind.ContextFinder.find(ContextFinder.java:414)
  at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:618)
  at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:565)
  at org.jpmml.model.JAXBUtil.getContext(JAXBUtil.java:126)
  at org.jpmml.model.JAXBUtil.createMarshaller(JAXBUtil.java:134)
  at org.jpmml.model.JAXBUtil.marshal(JAXBUtil.java:100)
  at org.jpmml.model.JAXBUtil.marshalPMML(JAXBUtil.java:90)
  at org.apache.spark.mllib.pmml.PMMLExportable.toPMML(PMMLExportable.scala:44)
  at org.apache.spark.mllib.pmml.PMMLExportable.toPMML(PMMLExportable.scala:78)
  ...
  Cause: java.lang.ClassNotFoundException: com.sun.xml.internal.bind.v2.ContextFactory
  at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:466)
  at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:566)
...

I hope we can fix these things in this way rather than profiles or command line args.

@squito
Copy link
Contributor Author

squito commented Feb 22, 2019

great, thanks for following up on this, Sean. As it sounds like you are doing a deeper dive here, and we can probably avoid the profile altogether, I will close this for now.

And thanks for the tip on -XX:-OmitStackTraceInFastThrow!

@squito squito closed this Feb 22, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants