summaryrefslogtreecommitdiff
path: root/test/dumpfm/millstone.clj
blob: d972a883ca4c0e22f64086dfe45aaae52b0b276a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
(ns dumpfm.millstone
  (:use clojure.contrib.def
	clojure.contrib.seq-utils
	clojure-http.client))

(def *spec*)
(def *cookies*)
(def *results*)

(def printer (agent nil))

(defn log [& args]
  (send printer (fn [_] (apply println args))))

(defmacro with-timing [e]
  `(let [s# (System/nanoTime)
         r# ~e
         f# (System/nanoTime)]
     [(float (/ (- f# s#) 1e6)) r#]))

(defn do-base-request [server path method cookies params]
  (let [method (.toUpperCase method)
	url    (str server path)]
    (if (= method "GET")
      (request (add-query-params url params) method nil cookies)
      (request url method nil cookies params))))

(defnk do-setup-request! [path
			  :params nil
			  :method "GET"]
  (let [res (do-base-request (:server *spec*) path method *cookies* params)]
    (if (:cookies res)
      (set! *cookies* (merge *cookies* (:cookies res))))
    res))

(defn- success? [resp]
  (= (:code resp) 200))

(defnk do-request! [path
		    :params nil
		    :method "GET"]
  (let [[ms resp] (with-timing
		      (try (do-base-request (:server *spec*)
					    path
					    method
					    *cookies*
					    params)
			   (catch Exception e
			     (log (format "Exception for %s - %s" path (.getMessage e)))
			     {:code "?" :msg "EXCEPTION"})))
	result      {:path       path
		     :ms         ms
		     :error      (if (success? resp) nil [(:code resp) (:msg resp)])}]
    (if (= (rand-int 100) 1)
      (log (format "%s - %.02fms" path ms)))
    (dosync
     (commute *results* conj result))
    resp))

(defn build-client! [spec client-id]
  (binding [*cookies*   {}]
    (if (:setup-func spec)
      ((:setup-func spec)))
    {:client-id client-id
     :cookies   *cookies*}))

(defn join [s lst]
  (apply str (interpose s lst)))

(defn sum [nums]
  (reduce + nums))

(defn avg [nums]
  (float (/ (sum nums) (count nums))))

(defn print-run-results [spec results elapsed-ms]
  (log (format "\nResults\n--------\n%s requests in %.02fs (%.02f r/s)\n%s clients"
	       (count results)
	       (/ elapsed-ms 1000)
 	       (/ (count results) (/ elapsed-ms 1000))
	       (:clients spec)))
  (let [avg-in-req (/ (sum (map :ms results)) (:clients spec))]
    (log (format "\nTime spent in requests per worker  : %.02fs (%.02f%%)"
		 (/ avg-in-req 1000)
		 (* (/ avg-in-req elapsed-ms) 100))))
  (doseq [[path rs] (group-by :path results)]
    (let [nums (map :ms rs)
	  errors (filter identity (map :error rs))]
      (log (format "\n%s:\n#: %s\nmin: %.02f ms\navg: %.02f ms\nmax: %.02f ms"
		   path
		   (count rs)
		   (apply min nums)
		   (avg nums)
		   (apply max nums)))
      (if-let [threshhold (:max-latency spec)]
	(let [timeouts (count (filter #(> % threshhold)
				      (map :ms rs)))]
	  (if (not (zero? timeouts))
	    (log (format "timeouts: %s (> %sms)" timeouts threshhold)))))
      (if (not (empty? errors))
	(log (format "errors: %s (%s)"
		     (count errors)
		     (join " " (sort (set errors))))))))
  (log ""))

(defn build-func-list [routes]
  (flatten (for [[n f] routes]
	     (repeat n f))))

(def num-updates 10)

(defn update-markers [reqs num]
  (set (map #(int (* % (/ reqs num))) (range 1 (inc num)))))

(defn grind! [spec]
  (binding [*spec* spec]
    (let [clients   (doall
		     (for [id (range (:clients spec))]
		       (build-client! spec id)))
	  reqs      (:requests spec)
	  funcs     (build-func-list (:funcs spec))
	  results   (ref [])
	  counter   (atom 0)
	  update-on (update-markers reqs num-updates)
	  threads   (doall
		     (for [c clients]
		       (Thread.
			(fn []
			  (binding [*spec*    spec
				    *cookies* (:cookies c)
				    *results* results]
			    (loop []
			      (let [c (swap! counter inc)]
				(if (<= c reqs)
				  (do ((rand-elt funcs))
				      (if (contains? update-on c)
					(log (format "Completed %s requests" c)))
				      (recur))))))))))]
      (log "Finished setup")
      (let [[elapsed _] (with-timing
			  (do
			    (doseq [t threads]
			      (.start t))
			    (doseq [t threads]
			      (.join t))))]
	(print-run-results spec @results elapsed)))))