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

--jvm tries to find Java executable system-wide. #11500

Open
wants to merge 27 commits into
base: develop
Choose a base branch
from

Conversation

Akirathan
Copy link
Member

@Akirathan Akirathan commented Nov 6, 2024

Fixes #11274

Pull Request Description

Fixes --jvm option, given to the native image. This was failing on my machine, because when given --jvm option, the runner was trying to find the java executable from the distribution manager's runtime (on my system located in ~/.local/share/enso/runtime) and it used the first runtime found. But the first runtime on my system is JDK 17.

The --jvm option now tries to:

  • Find a JDK from the distribution manager that has the same version as the JDK used for building the engine.
    • If there is not an exact version match, it tries to find a runtime from distribution manager that is newer.
    • If none, fallback to system-wide search
  • System-wide search tries to find java from $JAVA_HOME and from $PATH. But this is just a fallback.

Important Notes

  • Added test to Engine CI jobs that pass --jvm argument to a native image of engine-runner
  • runtime-version-manager sbt project migrated to a JPMS module
  • engine-runner now depends on runtime-version-manager.
  • Removed unnecessary stuff in runtime-version-manager dealing with outdated gu Graal Updater utility.
  • Extracted GraalVersionManager from RuntimeVersionManager

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • The documentation has been updated, if necessary.
  • Screenshots/screencasts have been attached, if there are any visual changes. For interactive or animated visual changes, a screencast is preferred.
  • All code follows the
    Scala,
    Java,
    TypeScript,
    and
    Rust
    style guides. In case you are using a language not listed above, follow the Rust style guide.
  • Unit tests have been written where possible.
  • If meaningful changes were made to logic or tests affecting Enso Cloud integration in the libraries,
    or the Snowflake database integration, a run of the Extra Tests has been scheduled.
    • If applicable, it is suggested to paste a link to a successful run of the Extra Tests.

@Akirathan Akirathan added the CI: No changelog needed Do not require a changelog entry for this PR. label Nov 6, 2024
@Akirathan Akirathan self-assigned this Nov 6, 2024
Copy link
Member

@JaroslavTulach JaroslavTulach left a comment

Choose a reason for hiding this comment

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

The --jvm option now tries to find java executable from JAVA_HOME and from PATH. If that is not found, the distribution manager's runtimes are used as a fallback.

I'd say that this is the wrong order. The target audience of Enso users is unlikely to have proper JVM installed in the system. Searching for a system JVM is good for us, developers, but not for our target audience.

trying to find the java executable from the distribution manager's runtime (on my system located in ~/.local/share/enso/runtime) and it used the first runtime found. But the first runtime on my system is JDK 17.

It is good we have such a failing example! What is the layout of your Enso JVM runtimes? That is an important information for your #11274 bug report.

Anyway, the enso launcher should:

  • search managed runtimes (in ~/.local/share/enso/runtime) first
  • ignore the outdated ones - e.g. having JVM spec version lower than 21 (right now)
  • select the exact match, if found
  • select acceptable match (e.g. newer JDK), if found - probably with some warning printed
  • if no match found among managed runtimes, fallback to system JVM - with some warning printed, if the JDK isn't exactly the one we expect

Would the above steps work for your system setup, Pavel?

@Akirathan
Copy link
Member Author

Searching for a system JVM is good for us, developers, but not for our target audience.

That is a good point.

It is good we have such a failing example! What is the layout of your Enso JVM runtimes? That is an important information for your #11274 bug report.

$ ls -l ~/.local/share/enso/runtime
drwxrwxr-x 1 pavel pavel 612 Nov  1  2023 graalvm-ce-java17.0.7-23.0.0
drwxrwxr-x 1 pavel pavel 114 Nov 28  2023 graalvm-ce-java21.0.1-23.1.0
drwxrwxr-x 1 pavel pavel 114 Feb 29  2024 graalvm-ce-java21.0.2-23.1.2
drwxrwxr-x 1 pavel pavel 114 Apr 16  2024 graalvm-ce-java21.0.2-24.0.0

Would the above steps work for your system setup, Pavel?

Certainly. Sounds like a good plan. I will see what I can do.

@JaroslavTulach
Copy link
Member

$ ls -l ~/.local/share/enso/runtime
drwxrwxr-x 1 pavel pavel 612 Nov  1  2023 graalvm-ce-java17.0.7-23.0.0
drwxrwxr-x 1 pavel pavel 114 Nov 28  2023 graalvm-ce-java21.0.1-23.1.0
drwxrwxr-x 1 pavel pavel 114 Feb 29  2024 graalvm-ce-java21.0.2-23.1.2
drwxrwxr-x 1 pavel pavel 114 Apr 16  2024 graalvm-ce-java21.0.2-24.0.0

It would be great, if we selected the same JDK as used for the build (however that's graalvm-community-openjdk-21.0.2+13.1 and I don't see it) and then try any JDK21 (probably the highest - e.g. graalvm-ce-java21.0.2-24.0.0) maybe with a warning...

Sounds like a good plan. I will see what I can do.

DistributionManager shall do most of the selection logic. CCing @radeusgd to give us an expert guidance.

Comment on lines 13 to 36
/**
* Tries to find {@code java} executable on the system. If a system-wide JDK is not found, tries
* to find it in the {@link DistributionManager distribution} runtimes.
*
* @return null if cannot be found. Otherwise, returns the absolute path to the executable, or
* simply {@code java} if it is on the {@code PATH}.
*/
static String findJavaExecutable() {
var javaHome = System.getenv("JAVA_HOME");
if (javaHome != null) {
var java = new File(javaHome, "bin/java").getAbsoluteFile();
if (java.exists()) {
return java.getAbsolutePath();
}
}
if (isJavaOnPath()) {
return "java";
}
var javaInRuntime = findJavaExecutableInDistributionRuntimes();
if (javaInRuntime != null) {
return javaInRuntime.toAbsolutePath().toString();
}
return null;
}
Copy link
Member

Choose a reason for hiding this comment

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

I think the precedence should actually look into distribution first and only afterwards use system JVM.

The whole purpose of ensoup was to manage JVMs related to the engine versions, so that the engine is run with the right compatible JVM and not a random version that may be incompatible with it (I guess it used to be more important before Truffle 'got unchained').

I think ideally we should first to run the JVM version required by the engine if it's found in the distribution. Then we can fallback to using the logic of searching JAVA_HOME and Path.

Ideally I'd also check the JVM version and log a warning if the version required by engine does not match the version that has been found.

Copy link
Member

@radeusgd radeusgd Nov 7, 2024

Choose a reason for hiding this comment

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

JVMs related to the engine versions

This version is stored in the engine's manifest - see for example built-distribution/enso-engine-0.0.0-dev-windows-amd64/enso-0.0.0-dev/manifest.yaml.

It contains fields: graal-vm-version and graal-java-version.
You can see lib/scala/runtime-version-manager/src/main/scala/org/enso/runtimeversionmanager/components/Manifest.scala for the logic of loading the manifest and extracting the GraalVMVersion from it.

We have a GraalCEReleaseProvider which translates this GraalVMVersion into a strategy for downloading it from GitHub - but you probably don't need this.

The function graalDirectoryForVersion in RuntimeVersionManager takes GraalVMVersion and gives you back the directory name under which this JVM version will be sitting in the $ENSO_DATA_DIRECTORY/runtime (installed by ensoup).

I guess you could factor out the Manifest and graalDirectoryForVersion utilities to a common package and you could use it to figure out the JVM version tied to the engine.


Btw. the manifest also contains a jvm-options field. I'd be very happy if we could keep the (sometimes changing) options in a single place.

Copy link
Member

Choose a reason for hiding this comment

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

I guess if you want to check if the JVM version is correct you need to call java --version and somehow parse its output and compare with graal-java-version.

e.g. I get

openjdk 21.0.2 2024-01-16
OpenJDK Runtime Environment GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30)
OpenJDK 64-Bit Server VM GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30, mixed mode, sharing)

I guess I want to extract the second word from the first line. At least for now that seems to work. But we can update the logic whenever the version format of expected JVM changes - unexpected format just means it's not the JVM we expect :)

Copy link
Member

Choose a reason for hiding this comment

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

Possibly better way than parsing output of java -version is to run a small program on the JVM:

public static void main(String... args) {
  System.out.prinltn(System.getProperty("java.vm.version"));
  // etc.
}

and just read the output line by line without the need to parse words.

Copy link
Member

Choose a reason for hiding this comment

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

Cool - that indeed sounds better, I didn't think of that

@Akirathan
Copy link
Member Author

As of 586fc73:

  • I have extracted GraalVersionManager from RuntimeVersionManager
    • Among other things, GraalVersionManager is able to list, and sort, all the installed runtimes in the distribution (in my case, it is inside ~/.local/share/enso/runtime)
  • engine-runner depends on runtime-version-manager
    • For that, I had to convert runtime-version-manager project to JPMS module.
  • Removed unnecessary stuff in runtime-version-manager dealing with outdated gu Graal Updater utility.
  • JavaFinder knows the exact version that was used for building -
    • And tries to find the runtime from the distribution with the exact version, or newer version

Only when there is no newer runtime found in the managed distribution runtimes, JAVA_HOME and system java is tried.

@Akirathan Akirathan added the CI: Clean build required CI runners will be cleaned before and after this PR is built. label Nov 8, 2024
Copy link
Member

@radeusgd radeusgd left a comment

Choose a reason for hiding this comment

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

Looks great!

Copy link
Member

@JaroslavTulach JaroslavTulach left a comment

Choose a reason for hiding this comment

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

Overall it looks very nice and clean. Some doubts:

  • does it work on Windows?
  • possibly too many exports from the new module-info

build.sbt Show resolved Hide resolved
build.sbt Show resolved Hide resolved
}
}
if (isJavaOnPath()) {
return "java";
Copy link
Member

Choose a reason for hiding this comment

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

Does that work on Windows?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't expect it to work on windows. This is a fallback that is currently only usable for devs and not anyone else. For all the other use-cases, the java exe should be found in the installed distribution runtimes.

@Akirathan
Copy link
Member Author

Akirathan commented Nov 14, 2024

Windows CI does not have java.exe on PATH - https://github.com/enso-org/enso/actions/runs/11840014687/job/32992849858?pr=11500#step:7:2539 . Removing this test from Windows again in 049b991

GitHub
Enso Analytics is a self-service data prep and analysis platform designed for data teams. - --jvm tries to find Java executable system-wide. · fb25d57

@radeusgd
Copy link
Member

Windows CI does not have java.exe on PATH - enso-org/enso/actions/runs/11840014687/job/32992849858?pr=11500#step:7:2539 . Removing this test from Windows again in 049b991

GitHub**--jvm tries to find Java executable system-wide. · enso-org/enso@fb25d57**Enso Analytics is a self-service data prep and analysis platform designed for data teams. - --jvm tries to find Java executable system-wide. · fb25d57

What about JAVA_HOME/bin?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: Clean build required CI runners will be cleaned before and after this PR is built. CI: No changelog needed Do not require a changelog entry for this PR.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

enso --jvm fails with InvalidModuleDescriptorException
3 participants