 (ns org.dada.core.test-clojure
     (:use 
      [clojure test]
+     [clojure.contrib math]
      )
     )
 
 (set! *warn-on-reflection* true)
 
+;;--------------------------------------------------------------------------------
 ;; test the speed of various bits of clojure to help ascertain which way DADA should do things
 
 (defmacro millis [times body]
   `(do
+     (System/gc)
      (print (quote ~body))
      (let [start# (System/currentTimeMillis)]
        (do (dotimes [_# ~times] ~body) nil)


;; seems to be true - but so close I can't rely on it not to fail build

;;(deftest assoc-vs-conj
;;  (is (faster 1 (reduce (fn [r i] (assoc r i i)) {} (range 3000000)) (reduce (fn [r i] (conj r [i i])) {} (range 3000000)))))

;; surely some mistake (on my part) here - I can look up a field in a record 100o x faster than I can in an array - I expected it to be faster, but...
;; this is down to reflection - investigate how to use an Object array efficiently
;; type hint was wrong - but why ?
(if (not (ibm?))
  (deftest record-vs-array-access
    (let [^Value r (Value. 0)
	  ^objects a (into-array Object [0])]
      (is (faster 1000000000 (.v r) (aget a 0))))))

;; but accessing a record field still appears to be 10 times faster than an array - is the int being boxed on the way out ?
(if (not (ibm?))
  (deftest record-vs-int-array-access
    (let [^Value r (Value. 0)
	  ^ints a (int-array [0])]
      (is (faster 1000000000 (.v r) (aget a 0))))))

;; no it's not autoboxing slowing down the int-array test - array access is slower than record access - by a factor of 10
(if (not (ibm?))
  (deftest record-vs-object-array-access
    (let [^Value r (Value. 0)
	  ^objects a (object-array [0])]
      (is (faster 1000000000 (.v r) (aget a 0))))))

(defrecord Foo (^int a))
(defrecord Bar (^Integer a))

;; int is faster (5x) - to be expected

;; (if (not (ibm?))
;;   (deftest record-int-vs-integer
;;     (let [f (Foo. 1)
;; 	  b (Bar. 1)]
;;       (is (faster 1000000000 (.a b)  (.a f))))))

;; interesting - reading an int out of a record and pssing it into
;; another fn (causing it to be auto-boxed) is still 5-10x faster than
;; just reading an Integer out of a record and passing it straight
;; into the same fn...

(if (not (ibm?))
  (deftest record-boxed-int-vs-integer
    (let [f (Foo. 1)
	  b (Bar. 1)]
      (is (faster 1000000000 (identity (.a b))  (identity (.a f)))))))
  
(import 'java.util.concurrent.locks.ReadWriteLock)
(import 'java.util.concurrent.locks.ReentrantReadWriteLock)
(import 'java.util.concurrent.locks.Lock)
(import 'java.util.Map)
(import 'java.util.HashMap)

;; (deftest rw-mutable-vs-immutable
;;   (let [lock ^ReadWriteLock (ReentrantReadWriteLock.)
;; 	wr (.writeLock lock)
;; 	m ^Map (HashMap.)
;; 	a (atom {})
;; 	n 10000000]
;;     (is (faster 1
;; 		(dotimes [i n] (try (.lock wr) (.put m i i) (catch Exception e)(finally (.unlock wr))))
;; 		(dotimes [i n] (swap! a conj [i i]))
;; 		))))

;; atom 4 times faster on J6/C1.3a4
;; (if (not (ibm?))

	 (println ": " elapsed# " millis")
	 elapsed#))))

(defmacro faster [times lhs rhs]
  `(let [l# (millis ~times ~lhs) r# (millis ~times ~rhs)] (< l# r#)))

(defmacro slower [times lhs rhs]
  `(let [l# (millis ~times ~lhs) r# (millis ~times ~rhs)] (> l# r#)))

(defmacro similar [times tolerance lhs rhs]
  `(let [l# (millis ~times ~lhs) r# (millis ~times ~rhs)] (< (abs (- l# r#)) ~tolerance)))

(defn ibm? []
  (.contains (.toLowerCase (System/getProperty "java.vm.vendor")) "ibm"))

;;--------------------------------------------------------------------------------

(defrecord Value [v])

;; (if (not (ibm?)) ;TODO - these assumptions do not hold true on IBM - maybe we should generate code accordingly ?
;;   (do
