Fork me on GitHub
#graalvm
<
2020-09-23
>
dominicm13:09:36

Oh yeah. I just wanted to actually measure the tradeoff for a common-ish use-case (web). I really want to build a $10/yr hobby project setup and it seems like native image might be important in that.

borkdude13:09:56

@dominicm for small hobby projects this may also be interesting: https://twitter.com/borkdude/status/1308737740788375552

borkdude21:09:00

Very happy to finally have figured out why clojure.pprint was bloating GraalVM binaries so much: https://github.com/borkdude/pprint tl;dr with only a minor change this can be fixed. If core team is interested, I'll make a patch. Alternatively I'll maintain a (cleaned up) fork of pprint with this minor adaptation.

👍 1
borkdude21:09:22

(and now I can finally swap out fipp with real pprint including cl-format in bb)

🎉 2
alexmiller22:09:43

what's the summary?

borkdude22:09:18

> table-ize uses find-var which tends to bloat GraalVM native images. > The find-var can be avoided by making write-option-table a table of keywords to vars.

alexmiller22:09:28

oh, I see there are words... reading :)

alexmiller22:09:28

so change keyword->symbol to keyword->var ?

alexmiller22:09:51

seems like that has negative impacts on non-graal load time?

alexmiller22:09:23

finding a var takes time?

alexmiller22:09:09

I think there are ways around that (like lazy loading those)

alexmiller22:09:40

but that's the kind of thing I'd look at. also whether anyone reaches into that private table ever

borkdude22:09:47

I'm not sure what you mean. This is the change I made (babashka.pprint ~ clojure.pprint).

(def ^{:private true} write-option-table
  {;:array            *print-array*
   :base             #'babashka.pprint/*print-base*
   ;;:case             *print-case*,
   :circle           #'babashka.pprint/*print-circle*
   ;;:escape           *print-escape*,
   ;;:gensym           *print-gensym*,
   :length            #'clojure.core/*print-length*
   :level             #'clojure.core/*print-level*
   :lines             #'babashka.pprint/*print-lines*
   :miser-width       #'babashka.pprint/*print-miser-width*
   :dispatch          #'babashka.pprint/*print-pprint-dispatch*
   :pretty            #'babashka.pprint/*print-pretty*
   :radix             #'babashka.pprint/*print-radix*
   :readably          #'clojure.core/*print-readably*
   :right-margin      #'babashka.pprint/*print-right-margin*
   :suppress-namespaces #'babashka.pprint/*print-suppress-namespaces*})

borkdude22:09:57

(the comments were already in there)

alexmiller22:09:44

my point is that when you load this ns, that's a lot more work than initializing the same table with symbols

borkdude22:09:59

isn't this AOT-ed?

alexmiller22:09:21

yes, but that doesn't matter

alexmiller22:09:31

you can't encode a var in bytecode

borkdude22:09:36

oh I see. well yeah, we can make it a delay probably

alexmiller22:09:39

you have to encode the instructions to load the var

alexmiller22:09:36

I mean you could even just delay the whole table and then force when needed

borkdude22:09:59

yeah, that's what I meant. But what are we talking about, nano-seconds probably?

alexmiller22:09:16

I'd guess more than that

alexmiller22:09:39

do you want to be the bad guy making Clojure startup slower? :)

alexmiller22:09:05

or is this some ulterior motive to force more people to graal?

borkdude22:09:43

pprint is already slow too load ;) j/k. yeah, I'd be happy to look into if this makes a difference or not. I didn't know (var foo.bar/baz) had an impact on startup time, so TIL

borkdude22:09:50

wrapping the table in a delay works for graalvm native-image as well, just tested it

alexmiller22:09:21

doing work is usually slower than not doing it :)

borkdude22:09:23

btw, pprint also uses a macro called binding-map which is I think the same as with-bindings

alexmiller22:09:55

that doesn't surprise me - pprint is kind of it's own body of work grafted into clojure :)

borkdude22:09:10

and it seems that write calls table-ize on every call, which is not needed since this is a static set of data

alexmiller22:09:44

it has a lot of things in it that give me pause when I read it, particularly from a perf pov

borkdude22:09:46

eh no I take that back, table-ize has options

borkdude22:09:58

yeah, it's pretty wild

alexmiller22:09:17

a lot of stuff is ported from common lisp stuff

borkdude22:09:40

I'll do some measurements on startup time and I'll get back to you

alexmiller22:09:50

I don't know if you've ever stumbled on it but there are some pprint docs written by Tom from when this was integrated

alexmiller22:09:45

but back to original question - feel free to file a jira with a patch and I'll take a look for 1.10.2

borkdude22:09:04

;; with delay
user=> (time (dotimes [i 100] (require '[babashka.pprint] :reload)))
"Elapsed time: 21165.989 msecs"
nil
;; without delay
user=> (time (dotimes [i 100] (require '[babashka.pprint] :reload)))
"Elapsed time: 24007.1286 msecs"
nil
;; with delay
user=> (time (dotimes [i 100] (require '[babashka.pprint] :reload)))
"Elapsed time: 27414.7834 msecs"
nil
;; without delay
user=> (time (dotimes [i 100] (require '[babashka.pprint] :reload)))
"Elapsed time: 30943.7437 msecs"

alexmiller22:09:15

I don't know if you saw that CLJ-2571 and CLJ-2572 went in

borkdude22:09:42

yeah, I saw it, nice :)

borkdude22:09:47

I'll have a look later this week, thanks for the advice so far

alexmiller22:09:47

so, not nanos eh

alexmiller22:09:27

although I guess that's not symbols to vars

borkdude22:09:13

keywords to vars

alexmiller22:09:46

I meant changing the map values from symbols to vars

alexmiller22:09:57

I just meant those timings above were comparisons from delay to no delay (I assume), not comparisons from table of symbols to table of vars

borkdude22:09:15

that's correct

borkdude22:09:50

I'll do those timings too. getting late here, going afk :)