clojure-dev

Issues: https://clojure.atlassian.net/browse/CLJ | Guide: https://insideclojure.org/2015/05/01/contributing-clojure/
2019-08-21T16:40:57.290900Z

It is reasonably common with Clojure/Java in a REPL to compile a function, run an expression using it with time to see some relatively long first run time, then you repeat it a few times, and if/when the JIT kicks in, you get a shorter run time, and continued runs repeat (with some variation) around that new lower run time.

2019-08-21T16:42:02.292200Z

I think I am seeing a case where, consistently, the first run of a function after defining it is faster than later runs, i.e. the pattern I can repeat is: define the function, first time run is fast, second through N-th time runs are relatively consistent times, about 3x longer than the first.

2019-08-21T16:42:19.292500Z

Perhaps a case where JIT is kicking in and making things worse?

bronsa 2019-08-21T16:42:35.292700Z

it can happen

bronsa 2019-08-21T16:42:55.293200Z

wouldn't say it's "reasonably common", but it's certainly possible

bronsa 2019-08-21T16:42:58.293400Z

do you have an example?

2019-08-21T16:43:33.293900Z

Function foo2 on this doc page: https://clojure.org/reference/java_interop#primitives

bronsa 2019-08-21T16:43:51.294100Z

uh, that looks innocent enough :)

2019-08-21T16:44:54.295100Z

Seen it with both AdoptOpenJDK 1.8.0 and 11 on macOS 10.13.6, Clojure 1.10.1, I doubt any special JVM options.

bronsa 2019-08-21T16:45:36.295400Z

just did a very unscientific run and it behaves as I'd expect on my machine (first run takes 1.8s, second 0.4, third 0.2, and then it oscillates between 0.14 and 0.16)

bronsa 2019-08-21T16:45:50.295800Z

would be interesting to see the jit log on yours

2019-08-21T16:47:38.296300Z

getting there ....

2019-08-21T16:59:22.296700Z

You mean the output when -XX:+PrintCompilation is enabld?

schmee 2019-08-21T17:47:43.298300Z

have you tried with Criterium, just for consistency?

2019-08-21T18:11:50.298800Z

I have now, and as I would have expected, it is consistent with the longer runs that occur not on the first time.

2019-08-21T18:13:51.299500Z

how are your fans? could power management be throttling things back as there is more activity?

2019-08-21T18:14:58.300500Z

Fan behavior is not changing between these runs, and each one of them is sub-second. Note that I can, after getting the longer run times, do the defn over again, and the first run after that is fast again, once, before repeated runs going back to slower speed.

cgrand 2019-08-21T18:39:14.304600Z

@andy.fingerhut it reminds me of something but I can’t remember exactly what. Two things: 1/ Do you see the same thing if you replace int by long? 2/ if you (def my-test #(foo2 1000000)) and then time my-test?

2019-08-21T18:42:50.304800Z

Will try those out soon here...

2019-08-21T18:46:44.305300Z

Replacing two occurrences of (int ...) with (long ...) gives same behavior.

2019-08-21T18:51:07.306200Z

Same fast-on-first-run, slower-on-second-and-later-runs behavior with your #2 suggestions. Goes back to one fast run if I re-do defn and def, but does not if I only re-evalute the def

cgrand 2019-08-21T18:52:34.306800Z

And if the def includes the call to time?

2019-08-21T18:53:44.307100Z

trying soon, but may be off-line for 20 mins or so.

2019-08-21T18:56:01.307300Z

same behavior

2019-08-21T19:13:13.308Z

@bronsa Out of curiosity what OS and JDK was your experiment on? I have yet to find a combo that doesn't exhibit this behavior, so far.

2019-08-21T19:26:57.309900Z

I got something vaguely similar, an undulating pattern of runtimes, where it settles down around 0.20-0.40 for me and after some number of calls might jump back up to 0.70-1.0 for a call(maybe triggering a gc?), then back down

2019-08-21T19:27:26.310300Z

I do not see how there is anything to GC here

2019-08-21T19:28:44.311200Z

but can try adding debug logging of occurrences of GC to my JVM startup options

2019-08-21T19:30:55.311600Z

@hiredman What OS and JDK are you running?

2019-08-21T19:33:10.312Z

but for the most part I see the first call slow, then faster and faster

2019-08-21T19:35:02.313200Z

linux, I've tried a few jvms, openjdk13, zulu 8, zulu 11, and corretto 11 (I think those are all openjdk based)

schmee 2019-08-21T19:53:36.313800Z

if you want to exclude GC from suspicion you can use Epsilon GC

2019-08-21T19:59:56.314200Z

I have enabled GC logging, and it does not occur during my tests

2019-08-21T20:00:09.314500Z

That simple function shouldn't be allocating any memory.

2019-08-21T21:26:22.316100Z

I also tried zulu 8, zulu 11, corretto 11 on Ubuntu 18.04 VM running on my local Mac laptop, and see the same behavior I have seen on other OS/JDK combos I have tried. I checked in a one-line shell script that runs a short Clojure program to automate this, since it was getting a little tedious to repeat by hand: https://github.com/jafingerhut/leeuwenhoek/blob/master/tryme.sh

2019-08-21T21:26:55.316500Z

I should probably try a bare metal Linux machine at some point.