Fork me on GitHub
#clojure-dev
<
2019-08-06
>
andy.fingerhut17:08:18

I know the full answer is "run performance tests and see", and/or "read the byte code produced by the Clojure compiler and think hard", but was looking for maybe quicker advice here. If there is some Clojure/Java code that frequently pulls 32-bit int's out of arrays, puts them into let-bound symbols, does a little bit of arithmetic and/or comparisons on them, and sometimes stores them back into int arrays, it is going to be perfectly normal to get boxed math warnings when one compiles the code using (set! *unchecked-math* :warn-on-boxed).

andy.fingerhut17:08:42

I believe that fn parameters can be type-hinted to be long or double primitive types, and the Clojure compiler can support passing those unboxed.

andy.fingerhut17:08:05

Can it support let-bound symbols as 32-bit int, unboxed? Or is that also restricted to long and double?

andy.fingerhut17:08:32

If not, then I am guessing perhaps the most efficient code can be produced in this scenario by converting to primitive long when pulling ints out of the arrays, manipulating them as long, then converting them back to int just before storing them back into int array.

alexmiller18:08:16

let bound symbols can be int prims I think

andy.fingerhut18:08:37

ok, good for me to do some focused experiments around that to verify it.

alexmiller18:08:57

the first 2 bullets there being the important ones

andy.fingerhut18:08:07

Resisting the urge to see when those docs were last updated -- They are definitely getting more impressive over time. Thanks!

alexmiller18:08:55

that's been there since 1.3 I think

ghadi18:08:03

FYI John Rose the JVM architect just filed an issue where hotspot doesn't apply loop optimizations when the trip counter is a long, only when it's an int

jumar07:08:25

Yes, this is related to such loops being considered "uncounted" . Some more surprising examples here: http://psy-lob-saw.blogspot.com/2016/02/wait-for-it-counteduncounted-loops.html ("Counted Loops?" section) Also here some notes about uncounted loops and their negative impact on optimizations: http://psy-lob-saw.blogspot.com/2015/12/safepoints.html (search for "negated")

andy.fingerhut18:08:23

That comment of mine was intended to express: "Wow, that is more than I remember reading there before, which may have been a long time ago", not "that looks old/out of date"

alexmiller18:08:54

I believe it is still accurate

alexmiller18:08:27

but I would check the generated bytecode to be sure

alexmiller18:08:06

I believe the intention is that you should be able to write hot loops on primitives though if you are sufficiently careful to avoid boxed calls

andy.fingerhut18:08:10

Excellent. Hopefully I can make this thing sing.

schmee18:08:18

0x000000011f8aced3: vmovdqu ymm0,YMMWORD PTR [r12+r10*8+0x10]
  0x000000011f8aceda: vmovdqu ymm1,YMMWORD PTR [r12+r8*8+0x10]
  0x000000011f8acee1: vpaddd ymm0,ymm1,ymm0
  0x000000011f8acee5: vmovdqu YMMWORD PTR [rax+0x10],ymm0

schmee18:08:26

that’s what I like to see! godmode

ghadi18:08:48

so it does inline across Fn's

ghadi18:08:10

that will be huge for Tensorflow-like libs on the JVM

schmee18:08:28

Java’s gettin’ fast

schmee18:08:37

and so is Clojure it seems 😄

souenzzo21:08:44

There is some odd edge cases on comment+reader-macro (clojure.tools.reader/read-string {:read-cond :allow} "[#_#?(:foo [])]")

gfredericks21:08:48

that's pretty weird

gfredericks21:08:15

I think it makes sense

gfredericks21:08:29

there's no :clojure expansion

gfredericks21:08:33

so it's equivalent to [#_]

👍 1
alexmiller21:08:34

#?(:foo []) yields nothing read

alexmiller21:08:15

not nil, but literally nothing

gfredericks21:08:43

reading [#_#?(:foo 42) 43 44] might make the behavior clear

alexmiller21:08:34

you could throw a :default branch in there to actually read as nil

alexmiller21:08:37

(read-string {:read-cond :allow} "[#_#?(:foo [] :default nil)]")