If you're trying to squeeze every last bit of performance, and you don't mind some messiness and macros, I noticed that many of these functions are called with only a few values in the first argument. So you are doing a lot of bit-fiddling at runtime that could be done at compile-time. So you could partially evaluate (i.e. unroll, i.e. ~make lookup table for) 'ldb' and 'dpb' for the 8 or 9 different first arguments you actually call it with. I unrolled your 'mask' fn into a 8-way case statement, and got about 6% speedup.
--Leif On Monday, February 23, 2015 at 1:59:32 PM UTC-5, danl...@gmail.com wrote: > > So, much of the pain involved in handling UUID's correctly on the JVM > relates to the fact that there is no primitive unsigned numeric type > that can represent the full range of possible values of the msb and lsb. > Ie., we need to always deal with the unpleasant "am I negative?" approach > to > reading (writing) that 64th bit. To avoid the complexity of all the > edge cases, we encapsulate the basic primitives of working with > unsigned numbers entirely within the abstraction of "mask" and > "mask offset". Using these, we built the two fundamental bitwise > operations > that are used for most of the UUID calculation: ldb (load-byte) and > dpb (deposit-byte). > > This scrap of code from my clj-uuid.bitmop library is extremely useful for > working > with "unsigned" long/binary values (analogously to how one might using the > common-lisp > functions by the same name). And, it has been "good enough" to do pretty > well > so far in terms of performance. But I'm sure that there are gifted > binariticians > in the audience that can improve this. (Note, the namespace uses > ztellman/primitive-math > which changes the semantics of some arithmetic operations and some type > hinting. Also > some of the 'let's are there for that reason. It may be helpful to refer > to the link. > > ;;; > https://github.com/danlentz/clj-uuid/blob/master/src/clj_uuid/bitmop.clj > > > (defn ^long expt2 [^long pow] > (bit-set 0 pow)) > > (defn ^long mask [^long width ^long offset] > (if (< (+ width offset) 64) > (bit-shift-left (dec (bit-shift-left 1 width)) offset) > (let [x (expt2 offset)] > (bit-and-not -1 (dec ^long x))))) > > (declare ^long mask-offset ^long mask-width) > > (defn ^long mask-offset [^long m] > (cond > (zero? m) 0 > (neg? m) (- 64 ^long (mask-width m)) > :else (loop [c 0] > (if (pos? (bit-and 1 (bit-shift-right m c))) > c > (recur (inc c)))))) > > (defn ^long mask-width [^long m] > (if (neg? m) > (let [x (mask-width (- (inc m)))] > (- 64 ^long x)) > (loop [m (bit-shift-right m (mask-offset m)) c 0] > (if (zero? (bit-and 1 (bit-shift-right m c))) > c > (recur m (inc c)))))) > > (defn ^long ldb > "Load Byte" > [^long bitmask ^long num] > (let [off (mask-offset bitmask)] > (bit-and (>>> bitmask ^long off) > (bit-shift-right num off)))) > > (defn ^long dpb > "Deposit Byte" > [^long bitmask ^long num ^long value] > (bit-or (bit-and-not num bitmask) > (bit-and bitmask > (bit-shift-left value (mask-offset bitmask))))) > -- 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.