Here's my findings:

Speed increase from most increase to least:
* Pre-sizing the HashSet - from 4.7ms to 3.7ms
* Inlining - from 4.7ms to 3.9ms
* Using point. constructor instead of ->point - from 2.4ms to 2ms
* Using non relfective HashSet init - from 2.36ms to 2.17ms
* Using iterator instead of doseq - from 2.17ms to 2.07ms

All in all, after this whole experiment, those would be my go to 
recommendations if wanting to optimize something in Clojure:

- If you are creating a lot of temporary structures use deftype for optimum 
performance, avoid records, and go for vectors and maps as a good middle 
ground.
- If you are adding a lot to a data-structure, resort to a mutable version 
for best performance.
- If using a mutable data-structure, try to pre-size them, if you plan on 
them growing a lot.
- If performance is critical, try inlining the functions you call most, 
things called from a loop are great candidates.
- Avoid using ->wtv style constructors, prefer wtv. instead for best 
performance.
- Avoid reflection and checked boxed math, especially if inside a loop.
- Try an iterator as the fastest way to iterate over a structure, though at 
this point, you're probably spending too much time optimizing.

On Tuesday, 15 November 2016 19:39:43 UTC-8, Didier wrote:
>
> Hey all,
>
> I came upon a benchmark of F#, Rust and OCaml, where F# performs much 
> faster then the other two. I decided for fun to try and port it to Clojure 
> to see how Clojure does. Benchmark link: 
> https://github.com/c-cube/hashset_benchs
>
> This is my code for it: 
> https://gist.github.com/didibus/1fd4c00b69d927745fbce3dcd7ca461a
>
> (ns hash-set-bench
>   "A Benchmark I modified to Clojure from:
>    https://github.com/c-cube/hashset_benchs";)
>
> (defn iterNeighbors [f [i j]]
>   (f [(dec i) j])
>   (f [(inc i) j])
>   (f [i (dec j)])
>   (f [i (inc j)]))
>
> (defn nth* [n p]
>   (loop [n n s1 #{p} s2 #{}]
>     (if (= n 0)
>       s1
>       (let [s0 (atom #{})]
>         (letfn [(add [p]
>                      (when (not (or (contains? s1 p) (contains? s2 p)))
>                        (reset! s0 (conj @s0 p))))]
>                (doseq [p s1] (iterNeighbors add p))
>                (recur (dec n) @s0 s1))))))
>
> #_(printf "result is %d" (count (time (nth* 2000 [0 0]))))
>
> And here's the F# code: 
> https://github.com/c-cube/hashset_benchs/blob/master/neighbors2.fsx
>
> Currently, this takes about 30s in Clojure, while it only takes around 3s 
> for OCaml, Rust and F#.
>
> From what I see, the differences between my code and theirs are:
>
>    - Lack of a Point struct, I'm just using a vector.
>    - They use a mutable set, I don't.
>    - They overrode Hashing for their point struct, as well as equality. I 
>    rely on Clojure's default hashing, and vector equality.
>
> I'm not sure if any of these things should really impact performance that 
> much though. And what I could do in Clojure if I wanted to improve it.
>
>
> Any Help?
>
>
> Thanks.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to