Why are you converting to a vector in the first place? Given that Clojure defaults to using longs for numbers that would mean using 64bit to represent one bit? With the additional overhead of PersistentVector this seems like a mad way to represent the entire thing?
Why not use something like .toLongArray or .toByteArray from BitSet instead?
Yes, I should be, and am, looking for other ways to represent the data.
It represents pixels on a 2D grid, and I have an API that expects it as a vector of [x y] points. I’ve tried to go at it a couple of different ways, but haven’t come around the performance problem with reading the bits.
Reflection is generally the #1 reason for slow Clojure code. Especially when used inside loops.
Other things to keep in mind sometimes is the use of checked math, for math heavy code, disabling the checks for overflows can help speed things up.
The fact that some reflection doesn’t show up with warn-on-reflection, specifically aget and aset don’t, and their multi-arity variant uses reflection under the hood making them super slow.
Then using sequences can slow things a bit if a lot of intermediate data is created, moving to transducers can help speed it up. Or loop/recur for utmost performance.
When using persistent data-structures and doing a lot of modification, transient can help speed things up. And some problems that really need fast updates or inserts/deletes can benefit from switching to arrays or using Java’s mutable data-structures instead.
Finally, primitive calls to loop/recur and functions can help speed boxing overhead in code that does a lot of primitive data manipulation.
Oh and I guess there’s also the use of protocols to speed up polymorphism if that’s an issue.