Embedding Julia in Scala

Hi,

I’m setting out to conduct a POC which calls Julia from Scala, via Julia’s C interface.

https://github.com/Quafadas/slincTest/blob/master/slinc.scala#L30

I’ve checked that I can call functions from the std C library.

I’ve compiled a trivial Julia library with package compiler.

From what I can tell, I’ve also generated bindings to the C interface of that Julia package from scala. I get this error message;

WARNING: failed to initialize stack walk info
ERROR: could not load library "C:\temp\superJlibCompiled\lib\julia\sys.dll"
The specified module could not be found.

I can track the warning back to Julia code, which I believe to be evidence, that I’ve successfully entered Julias init cycle, and have this called it’s C interface.

The subsequent error message is suggestive however, that something about the linking process has gone wrong, or is incomplete.

I can find a sys.dll file here;
C:\Users\partens\AppData\Local\Programs\Julia-1.8.3\lib\julia

But it would not be on the path. I followed the embedding instructions and have the

JULIA_DIR

environment variable set to
C:\Users\partens\AppData\Local\Programs\Julia-1.8.3\bin

I can overcome that, by simply copy and pasting
“C:\Users\partens\AppData\Local\Programs\Julia-1.8.3\lib\julia\sys.dll”

to the right place. Ultimately however, I get this;

Please submit a bug report with steps to reproduce this fault, and any error messages that follow (in their entirety). Thanks.
Exception: EXCEPTION_ACCESS_VIOLATION at 0x0 -- unknown function (ip: 0000000000000000)
in expression starting at none:0
unknown function (ip: 0000000000000000)
Allocations: 2907 (Pool: 2896; Big: 11); GC: 0

Given that I’m rather unsure what I’m doing, I’m unwilling to believe this is a bug report…

Would anyone have a hint?

I would look at this package to call Clojure, either to use (or to learn from):

Why bring it up? Just as Java can call Scala or Kotlin etc., and those languages can call Java, the same it true for Clojure.

I believe that project embeds Julia in the JVM, i.e. calling between languages is fast and reuses memory (and if I’m right about that, then it’s the only/first package I know of doing that). That’s unlike JavaCall.jl where you call the JVM, that runs in a separate process. JavaCall.jl has been used to call Scala, but then Julia is your top language. There might be a workaround, and yes with that other package Clojure, not Scala, is your top language.

I did find something more, maybe relevant or helpful:

1 Like

Hmmm… well, my clojure isn’t great… this scala works.

  juliaLib.jl_init()
  
  Scope.confined {
    println("Code supplied to Julia directly")    
    val t = Ptr.copy("print(sqrt(2.0))")
    juliaLib.jl_eval_string(t);
  }
  
  println("\n Now let's call a pre-compiled library")
  println(superJ.increment32(1))

In scala definitely works, I get this;

Code supplied to Julia directly
1.4142135623730951
 Now let's call a pre-compiled library

Please submit a bug report with steps to reproduce this fault, and any error messages that follow (in their entirety). Thanks.
Exception: EXCEPTION_ACCESS_VIOLATION at 0x0 -- unknown function (ip: 0000000000000000)
in expression starting at none:0
unknown function (ip: 0000000000000000)
Allocations: 2907 (Pool: 2896; Big: 11); GC: 0

So I’m increasiingly convinced this is something to do with linking / compling Julia libraries rather than scala. I suspect that my next step, should be to try and call this library from C, and see if that works.

It’s not problematic to call FROM Julia (to C; and indirectly to others), but in the other direction, embedding isn’t as easy. Even though the C API should just work for also C++, there’s a package to make it easier:

@Clemapfel
I’m just bringing it up since you could maybe learn from it, and also to make the point it doesn’t seem so non-trivial without a major project. So that Clojure project might help all JVM languages.

@cnuernber
Clojure has bidirectional interop with Java, and Java with Scala. I’m not sure, could you call straight from Scala to Clojure to Julia, or would you need to call from Scala to Java to Clojure to Julia…? I’m not sure, or could this project help with calling straight from Scala to Julia? I guess not without changing it/forking it.

So I’ve invested some time over the last days reading through the links here (my Clojure really sucks!), and my conclusion is that what I was hoping would be “easy”, is in fact “not easy”.

Backstory: There is another team, who want to write Julia. I was hoping to be able to offer them the ability to “wrap” that algorthimic special sauce. I’d have scala manage the data pipelining and end user experience. In the middle of all that, scala would call out to the C API of some Julia written by this other team.

Essentially, I was assuming that we could agree an interface, compile their code under some set of constraints, and call the C API of that “published” library. I was willing to endure some inconvenience to be able to offer that. However… based on the reading I’ve done and my experiments, “inconvenience” is not the right description!

Firstly, none of the commentary from the community I’ve read about embedding Julia says “this is going to go well and we encourage it”. Rather commentary tends to comes in one of two flavours:

  1. This is a major undertaking
  2. Don’t

Full disclosure: I have no intention (or in fact the skill) to undertake a “major project” myself.

In fact the “major project” I was hoping to be able to leverage was a scala project (slinc) which provides a really neat C interface and takes advantage of Javas foreign memory API. I have some confidence in that project. I can prove it works well for vanilla C, and it appears to work well for the trivial embedding Julia C API in the official docs. I’ve struggled to go beyond that trivial example however, and …

… I think the idea to seperately package up a user library looks (to me) unsolved / hard?

From what I can see of the projects referenced here;

  1. Jluna appears to offer a way to “mix” c and Julia, rather than cleanly “interface” them. It looks like an excellent piece of work … but not what I need, unless we’re willing to introduce a c++ compiler into the toolchain, which would be terrifying for everyone involved!

  2. The Clojure project again, looks like it solved the fundamental problems - an amazing piece of work. Frustratingly, I lack the understanding on how I could leverage it. It also looks somehow, like it assumes code is “shared” in the two projects rather than seperately compiled and interfaced. That has other implications such as a Julia runtime needing to be present. I’d concerns how we can really publish / collaborate cleanly without causing each other trouble.

I investigated PackageCompiler.jl, but that appears to dead end at some nasty function linking problem that looks far beyond my skill to tackle.

From everything I’ve seen, by far the closest candidate to what I’m looking for, is this;

Except it has a giant “Not Windows”, “highly experimental”," subset of Julia" caveat. And at that point, I’m likely causing trouble for the other team, rather than helping them.

If there’s something very wrong with what I’ve written above, I’d love to know… but … I think it’s project closed for me :-(. This is not possible with the tools / skill / resource I have at my disposal.

This will always be the case for Julia code, unless you manage to fit the code into the narrow constraints of StaticCompiler. Important functionality such as exceptions, threading, and memory allocation + garbage collection is handled by the runtime.

Interfacing two languages with runtimes is naturally potentially risky since they might have different expectations on how e.g. stacks and signals are handled. Although I have never used it myself I have seen several discussions of that kind of trouble for Javacall.jl and there are traces of that in its README.

If runtime issues can be overcome, the following may, or may not, be of interest.

At work we have a GUI application written in C++ using the QT library. For some use cases we want to call Julia for doing computations but for other use cases we don’t want to depend on Julia at all. The way we implement this is to use dlopen to load Julia on demand. This requires Julia to be installed on the computers where this functionality is used but has no implications on the GUI application itself, apart from a small amount of loading and interfacing code. Importantly users who don’t need the Julia functionality don’t need to have Julia installed and it doesn’t need to be bundled with the application.

Obviously there are a number of non-trivial technical details involved in implementing this. Those are all documented in GitHub - GunnarFarneback/DynamicallyLoadedEmbedding.jl: Embed Julia with dynamical loading of libjulia at runtime.

1 Like

Hi @Palli, I’m not well versed in clojure (nor julia :smile:), so I’m not totally sure I’m right on this, but the approach used by the Clojure library you linked is very different from the one @Simon_Parten is trying. @Simon_Parten is trying to pre-compile some julia code as a library, and call it with a C interface. The clojure code is using the C interface for embedded julia to interpret julia code at runtime. See here, where they load a julia source file from the jar resources and evaluate it.

@Simon_Parten I’m pretty sure this approach would work for you. You’ve already shown you can get Julia to evaluate in Scala, so you need only evaluate the code you want loaded, and then make calls to the specific functions you want to use.

Unfortunately, that will mean (for now) that you’d be sending raw strings as code to a julia interpreter, losing a lot of the nice interface Slinc provides. However, it should be possible to build an interface like Slinc to enable Scala ↔ Julia interop.

What do you think?

1 Like

Sharing memory between GC’d languages is challenging. You may have better luck with IPC. Perhaps send data or data filenames via a socket to a Julia compute server. Of course IPC introduces complexity, data redundancy, and communication costs, but it may be more manageable than the situation you describe.

1 Like

Thanks very much for this response - I think it’s very insightful. It is suggestive that my original dream is fact, something of a paradox. With Julia libraries (quite reasonably) relying on Julia’s runtime for the fundamental GC issues etc, then it’s clear you either need the runtime, or some heavily truncated subset of the language.

Your approach looks pretty cool. Congratulations on it!

I guess the only way to know is to try! But I’m really hazy on the implications of this. Loading up a bunch of files from a resource sounds simple enough … but I’m pretty lost on how the interop actually works! Whether there are major runtime penalties etc.

Does actually slinc help us at that point at all under this model or would be we essentially trying to invent slinj?

I’d love to find a way… but I’m very much out of my depth!

You would use Slinc under the covers of slinj to call the c embedding API, but that’s a very small time usage of Slinc.