This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-04-18
Channels
- # announcements (1)
- # aws (13)
- # beginners (55)
- # calva (8)
- # cider (73)
- # cljs-dev (96)
- # clojure (119)
- # clojure-europe (4)
- # clojure-italy (41)
- # clojure-nl (14)
- # clojure-uk (6)
- # clojurescript (90)
- # cursive (14)
- # data-science (1)
- # datomic (20)
- # dirac (1)
- # emacs (32)
- # figwheel-main (11)
- # fulcro (81)
- # hoplon (2)
- # jobs (1)
- # lein-figwheel (2)
- # luminus (1)
- # lumo (19)
- # nyc (3)
- # off-topic (60)
- # other-languages (1)
- # pedestal (5)
- # quil (1)
- # re-frame (3)
- # reagent (3)
- # reitit (5)
- # remote-jobs (1)
- # ring-swagger (2)
- # shadow-cljs (43)
- # sql (15)
- # tools-deps (20)
- # vim (21)
- # yada (6)
what does the ^not-native
type hint actually do? I’m trying to optimize some paths that use a lot of a particular protocol, which is extended to native JS types (string, number, nil) as well as CLJS/user types like Keyword, PersistentVector, and Object
it is an optimization that'll make the compiler skip checking if something implements a particular protocol fn
(defn foo [^not-native x] (bar x))
-> x.some$ns$TheProtocol$bar$artity$1()
vs x.some$ns$TheProtocol$bar$artity$1 ? x.some$ns$TheProtocol$bar$artity$1() : some.ns.bar(x)
if you are doing other stuff the overhead is not noticable indeed because pretty much everything else is more expensive
@lilactown but in your case you can't use it
Here are notes I've accumulated on that subject:
satisfies?
vs. implements?
and native-satisfies?
----
satisfies?
Normal, when you extend a protocol to a deftype or defrecord
implements?
like satisfies?
but does not check for natives that extend the protocol
Often used in conjunction with ^not-native
native-satisfies?
works if you extend to, say, object, or some native JS type
^not-native
type hint: In the presence of this type hint all protocol fns on the hinted symbol will be directly
dispatched under advanced compilation.
Frequent pattern in core:
cond
implements? (with ^not-native)
…
native-satisfies?
Not sure if all of this is still accurate, but it's stuff I jotted down a couple of years backOh, and one impression I get with all of the above is that it is really meant for internal use in the std lib. External code is probably best off avoiding ^not-native
and the other predicates, and simply sticking with satisfies?
I’m struggling with how to approach optimizing my library further. at this point I’m investigating trying to get rid of any calls to seq
, but that’s proving very difficult. I’m not even sure I’m going in the right direction
I have a lot of places that need to do ex. (-parse-element el (first args) (rest args))
that, and I have a memoization I’m doing and doing the deref + lookup seems to take quite some time
@lilactown well I've found that the profiles are useful to identity actual bottlenecks
I believe so:
with memoize: hx x 212,037 ops/sec ±1.75% (58 runs sampled)
without memoize: hx x 143,112 ops/sec ±1.95% (59 runs sampled)
those are benchmarks, and I’ve been staring at the chrome profile of the benchmark runs for the past 2 days
@lilactown I see I sucked you into the benchmark black hole 😛
but I got hx up to about 2/3 of reagent, which is a lot better than where it started!
@lilactown what is your top line item in self time? seq
?
it’s the confusing part of the profiles. my code is pretty much just calling other fns.
the only thing that the functions with high self-time really do is process the args into (first arg)
and (rest arg)
and then call another fn
so I’m kind of left guessing. maybe the calls to first/seq are getting inlined by the VM and it’s not reporting them as calls? I can’t really tell
this is bad if you want a hint https://github.com/Lokeh/hx/blob/master/src/hx/react.cljs#L26-L30
btw here is the current iteration: https://github.com/Lokeh/hx/blob/benchmark/src/hx/react.cljs
If it's any consolation, I've never had a profiler give me actionable information (python, java, js so far). I always have to make a semi-realistic benchmark workload and try things.
I think profilers are just bad at identifying death-by-many-cuts perf problems, especially sampling ones where the papercuts may not even show up
it sounds like you're already trying to optimize the "ligaments" of your code rather than the muscle
yeah. I think I may have squeezed out all there is to optimize what I have; I need to find a way to do what I’m doing, less
all the perf benefits in ClojureScript compile time runtime were all done via YourKit and Chrome
I’ve also found https://github.com/clojure-goes-fast/clj-async-profiler useful for JVM profiling
@lilactown another trick I've learned is that you have to squint a bit at profile results - esp self-time - it might not be the very top-line but there's no doubt it something in the top 30 items
I've often found it necessary to go through each item one by one and read the source body closely
this might not lead to the answer but it might hone your intuition about what's going wrong
it does also help to have some intuition about the kinds of optimizations that the JVM and JS engines do
many thing are non-obvious esp. for JS, like in the past the body of a try/catch would not be optimized
no native types in your protocol dispatch, avoid var ags w/o arity unrolling, no apply, etc.