-
Notifications
You must be signed in to change notification settings - Fork 327
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
Add Standard.Tableau to native-image #12204
base: develop
Are you sure you want to change the base?
Conversation
``` [warn] there's a key that's not used by any other settings/tasks: [warn] [warn] * runtime-compiler-dump / javaModuleName [warn] +- /home/hubert/tmp/enso/build.sbt:3425 [warn] [warn] note: a setting might still be used by a command; to exclude a key from this `lintUnused` check [warn] either append it to `Global / excludeLintKeys` or call .withRank(KeyRanks.Invisible) on the key ```
70MB in resources!? Are we distributing another |
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.
tableauhperap
i library should be extracted from the JAR into polyglot/lib
directory.
std-bits/tableau/src/main/resources/META-INF/native-image/org/enso/tableau/resource-config.json
Outdated
Show resolved
Hide resolved
This change extracts `Tableau`'s Hyper shared library from the jar. Unlike `Standard.Image`, had to provide a custom classloader that manages to find requested library - HyperAPI used a custom JNA logic for that.
return libPath; | ||
} | ||
} | ||
throw new UnsupportedOperationException("unable to find library " + libname); |
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.
Note: I'm not entirely sure this is the right way but RuntimeException
didn't feel right either.
Maybe a PanicException
or a simple null
?
Open for suggestions.
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 method is called only from HyperReader
. I suggested implementing finding native library this way, because HyperReader
is in std-bits
and, therefore, has no (direct) access to EnsoContext
and its NativeLibraryFinder
. I don't have a strong opinion about the exception. But I suggest you append additional test for it inside NativeLibraryFinderTest.
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.
If we are exposing this for the Enso code, then:
ctx.nothing()
might be a reasonable value.PanicException
is a good alternative as well- UnsupportedMessageException is a poor's man solution as well
Certainly not java.lang.UnsupportedOperationException
- that would mean crash of the interpreter!
Yes. |
return libPath; | ||
} | ||
} | ||
throw new UnsupportedOperationException("unable to find library " + libname); |
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 method is called only from HyperReader
. I suggested implementing finding native library this way, because HyperReader
is in std-bits
and, therefore, has no (direct) access to EnsoContext
and its NativeLibraryFinder
. I don't have a strong opinion about the exception. But I suggest you append additional test for it inside NativeLibraryFinderTest.
Hubert Plociniczak reports a new STANDUP for the provided date (2025-01-31): Progress: Created PR with Standard.Tableau integration. Looking into false positive log failures reported when closing project. It should be finished by 2025-02-01. Next Day: Next day I will be working on the #12204 task. Continue investigating the issue. |
} | ||
|
||
@Override | ||
public InputStream getResourceAsStream(String name) { |
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.
What is the caller stack trace? What the tableu code is trying to achieve? Why does it need InputStream
? Can we prevent it to ask for input stream?
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.
We can't prevent it. It's part of hyper initialization.
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.
My investigation suggests there is a way to prevent the call and skip the "extraction of the JNI library" completely.
int dotIdx = name.indexOf("."); | ||
if (libIdx != -1 && dotIdx != -1) { | ||
var libName = name.substring(libIdx + 3, dotIdx); | ||
var bindings = Context.getCurrent().getBindings("enso"); |
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.
Calling org.graalvm.polyglot
from ClassLoader
- that's wild.
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 only other option how to get reference to the NativeLibraryFinder
functionality is to move the NativeLibraryFinder
out of org.enso.runtime
into some module that is shared with std-bits. The approach via Context.getCurrent().getBindings("enso")
is what I have suggested to @hubertp as the "best" solution that I can think of. I am open to other suggestions of course.
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.
Care to expand on what's so wild about it?
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.
what's so wild about it?
ClassLoader
is a low level JVM mechanism. Calling from such a level into a Truffle language implemented on top of Truffle framework written in Java is just wild. It's like calling from a Linux kernel driver into X11 paint method and waiting for a result.
Doing something like this is a request to get a deadlock in internal JVM classloading locks.
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.
#yolo
Jokes aside, it would be best to suggest some improvements upstream as those jars are not integration-friendly. But that can take a lot of time and has unknown chances of success.
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 this "kernel to graphics" dependency, I'd like to point your attention to NetBeans translate support:
- it provides a way to instruct the classloader to do something else
- by having a special file that provides a mapping
- all NetBeans
ClassLoader
s support thistranslating
We could let the Enso tableau.jar
provide such a file to instruct the HostClassLoader
to return the FileInputStream
from getResourceAsStream
when a particular resource cannot be found.
The difference to current state is that we don't need to call into polyglot context from a ClassLoading
code.
@@ -88,7 +91,7 @@ private static HyperProcess getProcess() throws IOException { | |||
if (process == null || !process.isOpen()) { | |||
var contextClassLoader = Thread.currentThread().getContextClassLoader(); | |||
try { | |||
Thread.currentThread().setContextClassLoader(HyperReader.class.getClassLoader()); | |||
Thread.currentThread().setContextClassLoader(new TableauClassLoader()); |
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 seems to be:
$ javap -cp built-distribution/enso-engine-*/enso-*/lib/Standard/Tableau/0.0.0-dev/polyglot/java/tableauhyperapi.jar com.tableau.hyperapi.impl.SharedLibraryProvider
Compiled from "SharedLibraryProvider.java"
public interface com.tableau.hyperapi.impl.SharedLibraryProvider {
public abstract java.lang.String getSharedLibraryBaseName();
}
cannot it be used for loading the JNI library without these classloading tricks? Looks like the code checks jna.nounpack
property:
private static void registerJNA();
Code:
0: ldc #52 // String jna.nounpack
2: invokestatic #53 // Method java/lang/Boolean.getBoolean:(Ljava/lang/String;)Z
5: ifeq 17
8: invokestatic #54 // Method getLibraryBaseName:()Ljava/lang/String;
11: invokestatic #55 // Method com/sun/jna/Native.register:(Ljava/lang/String;)V
With a proper value provided, the code should be able to skip this extracting step completely.
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.
Yes, I saw that. Sadly I couldn't make it to work that way; JNA gets in the way.
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.
OK, thanks.
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.
Let me approve in the name of pragmatism. Since my previous review comment this PR managed to:
- make the distribution smaller:
- avoid duplicating the library between JAR and native executable
Only the
- makes the startup faster (no extraction of a resource on start)
remains open. That's probably good enough for now - especially when it is unlikely many people use Tableau to begin with.
I still don't like the "kernel to graphics call", but I can live with it. Moreover I am going to make another proposal to solve it and stay in the kernel space.
Seems to be causing problems on CI. Extraction logic had to be extended to allow for: - different prefixes (e.g, `linux-86-64` instead of `linux-86_64) - classes being present on the prefix should be included in the thin jar; we cannot assume that extraction prefix is unique
Hubert Plociniczak reports a new STANDUP for the provided date (2025-02-03): Progress: Addressing PR review - extracting native libs from Tableau's jars. Most problems come from discrepancies between different OS/Architecture. It should be finished by 2025-02-05. Next Day: Next day I will be working on the #12204 task. Continue investigating the issue. |
Alternative approach to deal with Windows/Mac failures on CI where `jnidispatch` native library somehow could not be identified. Linux worked just fine with the previous approach. This change enhances custom classloader to identify the desired library. That way we can provide the path to it, as specified in the implementation of JNA.
Hubert Plociniczak reports a new STANDUP for the provided date (2025-02-04): Progress: Continued fighting with native library loading - Tableau relies on JNA which brings its own set of problems. Solved for Linux but Windows and Mac are problematic. Dealing with some CI failures. It should be finished by 2025-02-05. Next Day: Next day I will be working on the #12204 task. Continue investigating the issue. |
Hubert Plociniczak reports a new STANDUP for yesterday (2025-02-05): Progress: Previous approach worked on linux because it was loading the library from jna-wrapper, failed to identify the reasons for failures for mac or windows due to setup issues. Attempting to hardcode jna boot dir path to fix the problem. Reviewing builtins PR. It should be finished by 2025-02-05. Next Day: Next day I will be working on the #12204 task. Continue investigating the issue. |
Pull Request Description
Closes #12194.
Checklist
Please ensure that the following checklist has been satisfied before submitting the PR:
screencast is preferred.
Scala,
Java,
TypeScript,
and
Rust
style guides. In case you are using a language not listed above, follow the Rust style guide.