I was curious about collecting your experiences in using graal + clj for AWS lambdas as opposed to cljs
@adam678 There are some people running babashka on AWS Lambda because of the fast startup, that is one example of a GraalVM binary
I guess the setup must be a lot easier as well
(Unrelated) Released dynaload 0.2.2 which gives better results than dynamic require in GraalVM binaries: https://github.com/borkdude/dynaload
@adam678 Check out for getting started with Clojure + GraalVM native-image: https://github.com/lread/clj-graal-docs
Using a native shared library from Python: https://github.com/borkdude/sci/blob/master/doc/libsci.md#using-libsci-from-python Thanks @sogaiu for the docs.
Nice tool for inspecting bytecode differences between 1.10.1 and 1.10.2-alpha wrt CLJ-1472:
$ clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.10.2-alpha1"} com.clojure-goes-fast/clj-java-decompiler {:mvn/version "0.3.0"}}}'
user=> (require 'clj-java-decompiler.core)
nil
user=> (clj-java-decompiler.core/decompile (locking (Object.) (+ 1 2 3)))
// Decompiling class: user$fn__192
import clojure.lang.*;
public final class user$fn__192 extends AFunction
{
public static Object invokeStatic() {
final Object lockee__5717__auto__195 = new Object();
final Number num;
synchronized (lockee__5717__auto__195) {
num = Numbers.num(Numbers.add(Numbers.add(1L, 2L), 3L));
}
return num;
}
@Override
public Object invoke() {
return invokeStatic();
}
}
nil
Just keep in mind this is a lie, perhaps a helpful lie, but still a lie
If you actually want to inspect bytecode differences you actually have to look at the bytecode
@borkdude may be you are familiar with this post already, but it touches on the "lie" bit iirc: http://clojure-goes-fast.com/blog/introspection-tools-java-decompilers/
thanks
All right, after experimenting a few hours and ironing out a few wrinkles, it turns out it is pretty easy using native-image for aws lambdas.
For a simple "hello $name" example, image size is 30mb and memory usage ~50mb. Not particularly lightweight in that regard, but execution duration is 1 ms
@adam678 I can get hello world down to 8MB
See: https://github.com/borkdude/dynaload/blob/master/graal-test/src/hello_world/core.clj
This is with 20.2.0 Java 11
@adam678 Note that you can control memory usage with the usual JVM flags -Xmx
etc, passed to the binary
@borkdude But here, the app also acts as a simple custom lambda runtime, so it needs to issue http requests and parse json (ie. add jsonista and clj-http-light to deps), even for a hello world kind of demo. That explains the image size. Memory usage still seems high for a couple of very simple http request, but I haven't played with -Xmx
and I am not sure how truly big it is in the context of a native image.
(Yes, using 20.2.0-r11 (thanks to your reflector fix plugin, well done 👏))
FWIW, babashka can do all that too
direct linking also helps for binary size
I will need to handle more complex use cases, but I wonder if babashka would help to keep things tight for those simpler ones, with the additional benefit that it wouldn't require long compilation time nor bothering with creating a runtime per app
that's the idea of bb yes
In this simple example direct linking changes virtually nothing regarding the size, I guess it would make more of an impact if the deps were more clojury. But anyway, shouldn't direct linking be the default for native images? Is there any benefit not to do so?
@adam678 yes, your binary and memory usage during compilation can spike significantly if you don't do that. https://epiccastle.io/blog/faster-graalvm-clojure-compilation-times/
A tip regarding http-kit and graalvm: https://github.com/http-kit/http-kit/issues/447