planck

Planck ClojureScript REPL
cgrand 2016-12-19T13:33:32.000088Z

I’ve got a weird behavior (in Planck only, not w/ Lumo)

cgrand 2016-12-19T13:34:09.000089Z

(defn bench [] (time (dotimes [_ 10000] (group-by odd? (range 256)))))
#'cljs.user/bench
cljs.user=> (dotimes [_ 10] (bench))
"Elapsed time: 1533.225609 msecs"
"Elapsed time: 1545.058830 msecs"
"Elapsed time: 1536.182743 msecs"
"Elapsed time: 1521.966733 msecs"
"Elapsed time: 1506.721830 msecs"
"Elapsed time: 1472.677051 msecs"
"Elapsed time: 1491.300766 msecs"
"Elapsed time: 1516.079173 msecs"
"Elapsed time: 1514.056357 msecs"
"Elapsed time: 1522.890919 msecs"
nil
cljs.user=> (bench)"Elapsed time: 1514.210034 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 1620.281140 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 1721.816597 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 1838.539985 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 2001.939968 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 2322.965899 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 2805.921760 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 3226.431841 msecs"
nil
`

cgrand 2016-12-19T13:34:45.000090Z

calling (bench) at the top level seems to cause some kind of leak

anmonteiro 2016-12-19T13:43:54.000091Z

I think Planck is monkey-patching the time measurement functions, so there might be a leak there :-)

cgrand 2016-12-19T13:44:55.000092Z

@anmonteiro wouldn’t the leak occur when time is called in a loop too? (first part of the repl log above)

anmonteiro 2016-12-19T13:44:59.000093Z

Node.js has its own high resolution timer so we don't need to do it in Lumo

anmonteiro 2016-12-19T13:45:15.000094Z

Hah weird

anmonteiro 2016-12-19T13:45:55.000096Z

I don't know how to answer that

cgrand 2016-12-19T13:47:00.000097Z

Hopefully @mfikes will have an idea.

cgrand 2016-12-19T13:47:53.000098Z

@anmonteiro have you moved to the US yet?

anmonteiro 2016-12-19T13:48:22.000099Z

Not yet, looks like it's going to be in early January!

mfikes 2016-12-19T14:08:02.000101Z

That is odd. I can’t repro it for some reason:

cljs.user=> (defn bench [] (time (dotimes [_ 10000] (group-by odd? (range 256)))#'cljs.user/bench
cljs.user=> (dotimes [_ 10] (bench))
"Elapsed time: 1159.593320 msecs"
"Elapsed time: 1144.919094 msecs"
"Elapsed time: 1157.564999 msecs"
"Elapsed time: 1123.972061 msecs"
"Elapsed time: 1139.588274 msecs"
"Elapsed time: 1152.520801 msecs"
"Elapsed time: 1137.451620 msecs"
"Elapsed time: 1146.951209 msecs"
"Elapsed time: 1143.448975 msecs"
"Elapsed time: 1143.177494 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 1189.568211 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 1159.490809 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 1135.291230 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 1132.313437 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 1136.998144 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 1205.367067 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 1144.274852 msecs"
nil
cljs.user=> (bench)
"Elapsed time: 1175.763460 msecs"
nil
But perhaps my box is under less memory pressure right now.

anmonteiro 2016-12-19T14:09:18.000102Z

Perhaps @cgrand isn't on the latest version?

cgrand 2016-12-19T14:10:05.000103Z

@anmonteiro I tried on latest release and a build from master a couple of days old

mfikes 2016-12-19T14:14:25.000104Z

I have noticed what appears to be a pattern where JavaScriptCore starts to slow down (and then speed up again), if it is either under memory pressure, or oddly decides to deopt things. So, what @cgrand shows is definitely something that can occur.

mfikes 2016-12-19T14:16:47.000105Z

One example is (time (apply + (range 1e7))) seems to fit in something that JavaScriptCore boils down to native code, but with 1e8 it can slow down upon repeated invocations.

mfikes 2016-12-19T14:17:14.000106Z

For example:

cljs.user=> (time (apply + (range 1e8)))
"Elapsed time: 555.519680 msecs"
4999999950000000
cljs.user=> (time (apply + (range 1e8)))
"Elapsed time: 1333.784931 msecs"
4999999950000000
cljs.user=> (time (apply + (range 1e8)))
"Elapsed time: 650.136291 msecs"
4999999950000000
cljs.user=> (time (apply + (range 1e8)))
"Elapsed time: 164.449090 msecs"
4999999950000000
cljs.user=> (time (apply + (range 1e8)))
"Elapsed time: 1387.819913 msecs”

cgrand 2016-12-19T14:18:19.000107Z

hmm I’m not sure that’s the same case

cgrand 2016-12-19T14:19:36.000108Z

I notice the slowdown only at top-level (but trying to fool that by wrapping in protective (#(…)) blankets is not enough)

cgrand 2016-12-19T14:20:42.000109Z

so if I invoke (bench) at the top level it gets sloooow. Then if after that I invoke (bench) in a loop: it’s back to fast. Then top-level again: slooooow.

mfikes 2016-12-19T14:21:52.000110Z

I’d like to understand the patterns in something like this:

cljs.user=> (dotimes [_ 15] (time (apply + (range 1e8))))
"Elapsed time: 92.477998 msecs"
"Elapsed time: 93.037535 msecs"
"Elapsed time: 96.071314 msecs"
"Elapsed time: 88.145049 msecs"
"Elapsed time: 110.345374 msecs"
"Elapsed time: 93.773480 msecs"
"Elapsed time: 145.159269 msecs"
"Elapsed time: 236.344057 msecs"
"Elapsed time: 543.034188 msecs"
"Elapsed time: 85.990809 msecs"
"Elapsed time: 1157.872663 msecs"
"Elapsed time: 600.583491 msecs"
"Elapsed time: 153.080935 msecs"
"Elapsed time: 1170.582053 msecs"
"Elapsed time: 1246.068331 msecs”

cgrand 2016-12-19T14:24:23.000111Z

;;failed attempt to escape top-level:
cljs.user=> (#(= (bench) %) *1)
"Elapsed time: 2235.353784 msecs"
false
cljs.user=> (#(= (bench) %) *1)
"Elapsed time: 2906.238506 msecs"
false
;; loop again
cljs.user=> (dotimes [_ 10] (bench))"Elapsed time: 2881.619693 msecs"
"Elapsed time: 2030.329689 msecs"
"Elapsed time: 1557.854658 msecs"
"Elapsed time: 1454.047283 msecs"
"Elapsed time: 1453.595620 msecs"
"Elapsed time: 1446.568025 msecs"
"Elapsed time: 1467.628626 msecs"
"Elapsed time: 1476.907106 msecs"
"Elapsed time: 1462.299794 msecs"
"Elapsed time: 1460.685129 msecs"
nil
;; back to slow (picking up where it was slow, not rebuilding “slowness” from the last (fast) run)
cljs.user=> (#(nil? (bench)))"Elapsed time: 3659.887264 msecs"
true

cgrand 2016-12-19T14:25:32.000112Z

@mfikes the difference between yours and mine is that yours degrades in dotimes while mine does not degrade in dotimes

mfikes 2016-12-19T14:26:19.000113Z

Perhaps there is something wrong with Planck: This works consistently in http://clojurescript.io in Safari: (with-out-str (time (apply + (range 1e8))))

cgrand 2016-12-19T14:28:52.000114Z

cljs.user=> (dotimes [_ 2] (bench))
"Elapsed time: 4572.871578 msecs"
"Elapsed time: 2918.273279 msecs” ; <- 2nd run gets better
nil
cljs.user=> (dotimes [_ 2] (bench))
"Elapsed time: 5467.805329 msecs"
"Elapsed time: 4465.643162 msecs"
nil
cljs.user=> (dotimes [_ 10] (bench))
"Elapsed time: 5442.148106 msecs"
"Elapsed time: 4066.061629 msecs"
"Elapsed time: 3183.890247 msecs"
"Elapsed time: 2285.270737 msecs"
"Elapsed time: 1986.569337 msecs"
"Elapsed time: 1875.215045 msecs"
"Elapsed time: 1888.828314 msecs"
"Elapsed time: 1942.992139 msecs"
"Elapsed time: 1674.563168 msecs"
"Elapsed time: 1571.186017 msecs”
nil
cljs.user=> (bench)
"Elapsed time: 6557.035676 msecs” ; <- so slooow again
`

mfikes 2016-12-19T14:29:45.000115Z

Perhaps there is some leak in Planck—perhaps I have it inadvertently holding onto something in the JS engine.

mfikes 2016-12-19T14:30:08.000116Z

I’ll log a ticket and dig into it.

cgrand 2016-12-19T14:31:13.000117Z

ok thanks

mfikes 2016-12-19T14:33:17.000118Z

https://github.com/mfikes/planck/issues/417

cgrand 2016-12-19T15:42:39.000121Z

How are top-level input processed?

mfikes 2016-12-19T17:22:52.000122Z

@cgrand Any form is compiled to JavaScript and then evaluated in the VM. If you pass -v to either Planck or Lumo, you will see the JavaScript emitted and evaluated.