This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-09-09
Channels
- # aws (1)
- # babashka (61)
- # bangalore-clj (5)
- # beginners (83)
- # biff (2)
- # calva (4)
- # cider (6)
- # clara (5)
- # clj-kondo (72)
- # cljs-dev (31)
- # cljsrn (28)
- # clojure (8)
- # clojure-australia (1)
- # clojure-europe (19)
- # clojure-france (1)
- # clojure-losangeles (21)
- # clojure-nl (2)
- # clojure-spec (2)
- # clojure-uk (9)
- # clojurescript (13)
- # clojureverse-ops (5)
- # code-reviews (1)
- # conjure (7)
- # cursive (4)
- # datascript (2)
- # datomic (8)
- # depstar (1)
- # emacs (3)
- # etaoin (1)
- # events (3)
- # exercism (7)
- # fulcro (6)
- # girouette (2)
- # graalvm (125)
- # honeysql (19)
- # integrant (1)
- # jobs (12)
- # lsp (1)
- # numerical-computing (1)
- # off-topic (23)
- # portal (12)
- # practicalli (1)
- # re-frame (35)
- # reitit (5)
- # releases (1)
- # remote-jobs (1)
- # shadow-cljs (51)
- # tools-deps (14)
- # vim (3)
- # xtdb (20)
Morning all I’ve come across a curious runtime quirk regarding the slow initialisation of the Cognitect AWS API in Lambda. My code uses Holy Lambda and is natively compiled with GraalVM. In summary, I’m sending an SQS message and for a cold start up, the initialisation is very slow - about 2 seconds. However, I have other lambda functions, same util function, that do not exhibit the same slow down: the first SQS call is about 180ms on a cold start. After diving deeper into this, The slowdown seems to be related to memory. Same code, different memory settings:
BEFORE (Mem 192 MB):
REPORT RequestId: ca6134cd-cc0c-5d20-b6dc-6d7f3f9173b4 Duration: 3110.14 ms Billed Duration: 3348 ms Memory Size: 192 MB Max Memory Used: 137 MB Init Duration: 237.14 ms
AFTER (Mem 2000 MB):
REPORT RequestId: 760df43d-ded0-5dff-97ae-ad8e1873c3ff Duration: 425.65 ms Billed Duration: 718 ms Memory Size: 2000 MB Max Memory Used: 142 MB Init Duration: 291.85 ms
I found this to be surprising.
For regular Java, I get it - you’d be stressing the different mem generations by splitting up such a small amount of RAM.
But GraalVM - I’m not sure if that’s a thing or not
Even so, as you can see, the reported memory used is 142 MB in both cases which is well under both memory specifications.
Can anyone offer some insight into this? Or advice on how to choose the right amount of memory?For reference, SQS util function is this:
(ns sqs-utils
(:require
[io.pedestal.log :as log]
[cognitect.aws.client.api :as aws]
[ai.scalably.lambda.common.aws-utils :refer [http-client]]))
(def sqs (delay (aws/client {:api :sqs
:http-client @http-client})))
(defn send-sqs-message!
[{:keys [queue-url, msg] :as request}]
(log/debug :in 'send-sqs-message! :request request)
(let [result (time (aws/invoke @sqs {:op :SendMessage
:request {:QueueUrl queue-url
:MessageBody msg}}))
error-message (or (:cognitect.anomalies/message result) (get-in result [:ErrorResponse :Error :Message]))]
(if error-message
(log/error :in 'send-sqs-message! :message "Failed to send SQS message" :error-message error-message :request request :result result)
(log/info :in 'send-sqs-message! :message "Sent SQS message" :request request :result result))
(:MessageId result)))
At the advice of @UJ1339K2B I’ve raised this on the GraalVM Slack channel https://graalvm.slack.com/archives/CN9KSFB40/p1631178165056200 I’ll post back any findings here.
it may be related with memory pressure with max at 200, when you reach 100, it is 50% with max at 2000, when you reach 100, it is 5% 50% will trigger GC methods more than 5% Not sure if you can connect something like a visualvm into your app. visualvm will show gc activity
@U2J4FRT2T thanks for this. I’m operating on this assumption also. Lambdas are ephemeral and locked down, so being able to use visual vm is unlikely. You can get the JVM to log GC activity. Been a while since I’ve pored through such content, but I think that’s my only option.
Hey ho! We’ve moved lread/clj-graal-docs
to clj-easy/graal-docs
This happy new home better reflects that it is a community-built set of docs.
(Thanks to @borkdude and @ericdallo for creating the new clj-easy
github org!)
well, I watched Simple Made Easy like 10 times last week
so we don't have to deal with lots of PRs, we're also considering JIRA and mailing patches :P
The base-64 code is read via OCR, and if the final result of the patch is not syntactically-correct Clojure code, the entire suggestion is disregarded out of hand.
After all, if it wasn't worth spending the time to get it right the first time, it wasn't worth it at all.
If you don’t hear back from us in 3 years, please assume rejection and consider resubmitting, but please, more carefully.
that sounds like something that'd come out of the js ecosystem
I gotta question if the coffee brown color for java was intentional or a happy coincidence for github's language colors.
on the upside, this did cause me to register http://knittedcastle.org
There's probably copyright on this thing? https://www.theguardian.com/lifeandstyle/gallery/2011/jun/22/ten-spectacular-knitted-creations-in-pictures#img-8
@ericdallo it works: https://github.com/clj-easy/graal-build-time also: I used tools.build and bb tasks together :)
Still need to insert the logic that collects all the packages but that's the trivial part
[native-test:73977] classlist: 1,082.78 ms, 0.96 GB
[native-test:73977] (cap): 1,431.59 ms, 0.96 GB
Registering packages for build time initialization: clojure, clj_easy
yeah please test. one thing I have doubts about is whether this Feature class sees the classpath of the app under build or not
@ericdallo Testing locally...
but I think we can use this https://www.graalvm.org/sdk/javadoc/org/graalvm/nativeimage/hosted/Feature.FeatureAccess.html
Registering packages for build time initialization: clojure, rewrite_clj.interop, rewrite_clj.zip, rewrite_clj.node, rewrite_clj.parser.namespaced_map, rewrite_clj.parser.whitespace, rewrite_clj.parser.token, rewrite_clj.parser.core, rewrite_clj.parser.keyword, rewrite_clj.parser.string, rewrite_clj.zip.subedit, rewrite_clj.zip.move, rewrite_clj.zip.whitespace, rewrite_clj.zip.context, rewrite_clj.zip.findz, rewrite_clj.zip.seqz, rewrite_clj.zip.removez, rewrite_clj.zip.base, rewrite_clj.zip.editz, rewrite_clj.zip.insert, rewrite_clj.zip.walk, rewrite_clj.parser, rewrite_clj.custom_zipper.utils, rewrite_clj.custom_zipper.switchable, rewrite_clj.custom_zipper.core, rewrite_clj.paredit, rewrite_clj.reader, rewrite_clj.node.namespaced_map, rewrite_clj.node.comment, rewrite_clj.node.regex, rewrite_clj.node.fn, rewrite_clj.node.reader_macro, rewrite_clj.node.coercer, rewrite_clj.node.whitespace, rewrite_clj.node.meta, rewrite_clj.node.protocols, rewrite_clj.node.forms, rewrite_clj.node.token, rewrite_clj.node.integer, rewrite_clj.node.seq, rewrite_clj.node.extras, rewrite_clj.node.uneval, rewrite_clj.node.keyword, rewrite_clj.node.stringz, rewrite_clj.node.quote, org.httpkit.sni_client, org.httpkit.server, org.httpkit.client, org.httpkit.encode, cognitect.transit, sci.impl.vars, sci.impl.faster, sci.impl.interop, sci.impl.hierarchies, , sci.impl.for_macro, sci.impl.reify, sci.impl.fns, sci.impl.multimethods, sci.impl.analyzer, sci.impl.unrestrict, sci.impl.load, sci.impl.protocols, sci.impl.types, sci.impl.doseq_macro, sci.impl.records, sci.impl.interpreter, sci.impl.resolve, sci.impl.utils, sci.impl.parser, sci.impl.callstack, sci.impl.macros, sci.impl.opts, sci.impl.proxy, sci.impl.read, sci.impl.evaluator, sci.impl.core_protocols, sci.impl.destructure, sci.impl.namespaces, sci.addons, sci.addons.future, sci.core, sci.lang, io.aviso.ansi, io.aviso.columns, io.aviso.exception, edamame.impl.parser, edamame.impl.read_fn, edamame.impl.syntax_quote, flatland.ordered.common, flatland.ordered.map, flatland.ordered.set, bencode.core, taoensso.timbre, taoensso.encore, taoensso.truss, taoensso.timbre.appenders.core, taoensso.truss.impl, hf.depstar.uberjar, clj_yaml.core, cheshire.core, cheshire.factory, cheshire.generate_seq, cheshire.generate, cheshire.parse, selmer.tags, selmer.filter_parser, selmer.filters, selmer.util, selmer.parser, selmer.template_parser, selmer.validator, hiccup.util, hiccup.compiler, babashka.impl.rewrite_clj, babashka.impl.bencode, babashka.impl.yaml, babashka.impl.csv, babashka.impl.httpkit_client, babashka.impl.tools.cli, babashka.impl.cheshire, babashka.impl.common, babashka.impl.reify, babashka.impl.server, babashka.impl.error_handler, babashka.impl.clojure.zip, babashka.impl.clojure.core.server, babashka.impl.clojure.test.check, , babashka.impl.clojure.java.shell, babashka.impl.clojure.java.browse, babashka.impl.clojure.data, babashka.impl.clojure.core, babashka.impl.clojure.test, babashka.impl.clojure.stacktrace, babashka.impl.clojure.main, babashka.impl.curl, babashka.impl.deps, babashka.impl.match, babashka.impl.socket_repl, babashka.impl.httpkit_server, babashka.impl.protocols, babashka.impl.hiccup, babashka.impl.data, babashka.impl.classes, babashka.impl.xml, babashka.impl.features, babashka.impl.datafy, babashka.impl.logging, babashka.impl.pprint, babashka.impl.print_deps, babashka.impl.tasks, babashka.impl.proxy, babashka.impl.test, babashka.impl.repl, babashka.impl.process, babashka.impl.sigint_handler, babashka.impl.transit, babashka.impl.async, babashka.impl.pipe_signal_handler, babashka.impl.selmer, babashka.impl.classpath, babashka.impl.pods, babashka.impl.fs, babashka.impl.ordered, babashka.nrepl.impl.server, babashka.nrepl.impl.utils, babashka.nrepl.server, babashka.wait, babashka.curl, babashka.pods.impl.resolver, babashka.pods.sci, babashka.pods.impl, babashka.process, babashka.main, babashka.fs, borkdude.deps, aaaa_this_has_to_be_first_because_patches, clj_easy.graal_build_time, borkdude.graal.locking, selmer.node
did you implement that logic of using babashka instead of babashka.impl for example?
Ah this looks much better:
Registering packages for build time initialization: clojure, rewrite_clj, org, cognitect, sci, io, edamame, flatland, bencode, taoensso, hf, clj_yaml, cheshire, selmer, hiccup, babashka, borkdude, aaaa_this_has_to_be_first_because_patches__init.class, clj_easy
well, ATM we are including everything with just the --initialize-at-build-time
right?
this is my commit: https://github.com/babashka/babashka/commit/fac5d78ebe39d6a3137de33170da542445c19649
if you're using cheshire, then you'll also need:
--initialize-at-build-time=com.fasterxml.jackson
since cheshire uses some jackson object at the top level I thinkthanks, clojure-lsp doesn't use cheshire though, but I image other libs that do things like that would require the same
(but on Windows in the directory thing you should use the proper OS-specific character)
I successfully removed digest from clojure-lsp, but still getting one last issue with java.sql.SQLException
:
Using CLibrary: com.oracle.svm.core.posix.linux.libc.GLibC
To see how the classes got initialized, use --trace-class-initialization=java.sql.SQLException
[clojure-lsp:582146] analysis: 100,076.15 ms, 3.83 GB
Error: Classes that should be initialized at run time got initialized during image building:
java.sql.SQLException the class was requested to be initialized at run time (from jar:file:///home/greg/dev/clojure-lsp/clojure-lsp.jar!/META-INF/native-image/clojure-lsp/clojure-lsp/native-image.properties with 'java.sql'). To see why java.sql.SQLException got initialized use --trace-class-initialization=java.sql.SQLException
com.oracle.svm.core.util.UserError$UserException: Classes that should be initialized at run time got initialized during image building:
java.sql.SQLException the class was requested to be initialized at run time (from jar:file:///home/greg/dev/clojure-lsp/clojure-lsp.jar!/META-INF/native-image/clojure-lsp/clojure-lsp/native-image.properties with 'java.sql'). To see why java.sql.SQLException got initialized use --trace-class-initialization=java.sql.SQLException
at com.oracle.svm.core.util.UserError.abort(UserError.java:68)
at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.checkDelayedInitialization(ConfigurableClassInitialization.java:555)
at com.oracle.svm.hosted.classinitialization.ClassInitializationFeature.duringAnalysis(ClassInitializationFeature.java:169)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$runPointsToAnalysis$12(NativeImageGenerator.java:730)
at com.oracle.svm.hosted.FeatureHandler.forEachFeature(FeatureHandler.java:71)
at com.oracle.svm.hosted.NativeImageGenerator.runPointsToAnalysis(NativeImageGenerator.java:730)
at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:532)
at com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:491)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:380)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:543)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:119)
at com.oracle.svm.hosted.NativeImageGeneratorRunner$JDK9Plus.main(NativeImageGeneratorRunner.java:573)
[clojure-lsp:582146] [total]: 109,298.94 ms, 3.83 GB
# Printing build artifacts to: /home/greg/dev/clojure-lsp/clojure-lsp.build_artifacts.txt
Error: Image build request failed with exit status 1
com.oracle.svm.driver.NativeImage$NativeImageError: Image build request failed with exit status 1
at com.oracle.svm.driver.NativeImage.showError(NativeImage.java:1916)
at com.oracle.svm.driver.NativeImage.build(NativeImage.java:1584)
at com.oracle.svm.driver.NativeImage.performBuild(NativeImage.java:1545)
at com.oracle.svm.driver.NativeImage.main(NativeImage.java:1532)
This could very well be because you are using some sql stuff on the top level in your code
I don't see any top level sql thing on clojure-lsp.db, maybe it comes from :
[next.jdbc :as jdbc]
[next.jdbc.result-set :as rs]
?it seems --initialize-at-build-time=java.sql.SQLException
worked, but I'll debug who is doing that
voidlinux now packages babashka in it's main repo, all built from source. Surprisingly it's built using "mandrel" instead of graal: https://github.com/graalvm/mandrel which is pretty cool
this might be the work of @U01FQSYHRCY :)
Indeed. 😉 I couldn't get GraalVM to build with musl.
@U01FQSYHRCY But mandrel doesn't support musl at all right?
it does
needs light patching to support musl as a system libc