rlm@0: (ns rlm.iterate rlm@0: "from the clojure mailing list" rlm@0: {:author "tsuraan"} rlm@0: (:gen-class rlm@0: :name "iterate" rlm@0: :main true rlm@0: )) rlm@0: rlm@0: rlm@0: (set! *warn-on-reflection* true) rlm@0: (import java.io.FileInputStream) rlm@0: rlm@0: (def *numbytes* (* 16 1024 1024)) rlm@0: rlm@0: rlm@0: (defmacro better-areduce [a idx ret init expr] rlm@0: `(let [a# ~a rlm@0: alength# (alength a#)] rlm@0: (loop [~idx (int 0) ~ret ~init] rlm@0: (if (< ~idx alength#) rlm@0: (recur (unchecked-inc ~idx) ~expr) rlm@0: ~ret)))) rlm@0: rlm@0: (defn translated-countnl rlm@0: [#^bytes buf] rlm@0: (let [total-length (alength buf)] rlm@0: (loop [count (int 0) current-index (int 0)] rlm@0: (if (>= current-index total-length) rlm@0: count rlm@0: (let [new-count rlm@0: (if (= (aget #^bytes buf current-index) (byte 10)) rlm@0: (unchecked-inc count) rlm@0: count)] rlm@0: rlm@0: (recur new-count (unchecked-inc current-index))))))) rlm@0: rlm@0: (defn countnl-classic rlm@0: [#^bytes buf] rlm@0: (let [nl (byte 10)] rlm@0: (areduce buf idx count 0 rlm@0: (if (= (aget buf idx) nl) rlm@0: (inc count) rlm@0: count)))) rlm@0: rlm@0: rlm@0: (defn countnl-lite rlm@0: "this is the absolute fastest function I could come up with. rlm@0: still 2.25 times slower that the java version." rlm@0: [#^bytes buf] rlm@0: (areduce buf idx count (int 0) rlm@0: (if (= (clojure.lang.RT/aget buf idx) 10) rlm@0: (unchecked-add count 1) rlm@0: count))) rlm@0: rlm@0: rlm@0: (defn #^Boolean is-ten? [#^Integer A] rlm@0: (= A 10)) rlm@0: rlm@0: (defn countnl-max-power rlm@0: [#^bytes buf] rlm@0: (areduce buf idx count (int 0) rlm@0: (if (is-ten? (clojure.lang.RT/aget buf idx)) rlm@0: (unchecked-inc count) rlm@0: count))) rlm@0: rlm@0: rlm@0: rlm@0: rlm@0: rlm@0: rlm@0: rlm@0: rlm@0: rlm@0: rlm@0: rlm@0: "(times are averages with 10 rounds) rlm@0: no-modifications rlm@0: classic: 198.151 rlm@0: lite: 186.668 rlm@0: rlm@0: unchecked-inc rlm@0: classic: 177.938 rlm@0: lite: 129.604 rlm@0: rlm@0: inlined-let rlm@0: classic: 202.604 rlm@0: lite: 195.357 rlm@0: rlm@0: make nl a constant rlm@0: classic: rlm@0: lite: 361.734 rlm@0: rlm@0: make nl a constant with type hint rlm@0: lite: 394.45 rlm@0: rlm@0: literal 10, no let rlm@0: lite: 102.876 rlm@0: rlm@0: (int 10) instead of literal 10 rlm@0: lite: 194.904 rlm@0: rlm@0: (unchecked-add count 0) instead of count rlm@0: lite: 209.186 rlm@0: rlm@0: direct reference to RT/aget, bypassing int cast rlm@0: lite: 99.767 rlm@0: rlm@0: (int 0) instead of 0 initialization of count rlm@0: lite: 66.446 rlm@0: rlm@0: make nl an (int 10) instead of (byte 10) rlm@0: lite: 180.003 rlm@0: " rlm@0: rlm@0: rlm@0: rlm@0: rlm@0: rlm@0: (defmacro time-multi rlm@0: "Evaluates expr and prints the time it took. Returns the value of rlm@0: expr." rlm@0: {:added "1.0"} rlm@0: [expr] rlm@0: `(let [start# (. System (nanoTime)) rlm@0: ret# ~expr rlm@0: end# (/ (double (- (. System (nanoTime)) start#)) 1000000.0)] rlm@0: (prn (str "Elapsed time: " end# " msecs")) rlm@0: [ret# end#])) rlm@0: rlm@0: rlm@0: rlm@0: (defn run [countnl-impl] rlm@0: (let [ifs (FileInputStream. "/dev/urandom") rlm@0: buf (make-array Byte/TYPE *numbytes*) rlm@0: runs 10] rlm@0: (loop [n 0 total-time 0] rlm@0: (if (= n runs) (/ total-time runs) rlm@0: (let [sz (.read #^FileInputStream ifs buf)] rlm@0: (println "Wanted" *numbytes* "got" sz "bytes") rlm@0: (let [[count time] (time-multi (countnl-impl buf))] rlm@0: (println "Got" count "nls") rlm@0: (recur (inc n) (+ total-time time)))))))) rlm@0: rlm@0: (defn -main [& ignore] rlm@0: (run countnl-lite) rlm@0: (run countnl-classic) rlm@0: ) rlm@0: rlm@0: rlm@0: