|
1 | 1 | (ns compojure.api.perf-test |
2 | 2 | (:require [compojure.api.sweet :refer :all] |
3 | | - [compojure.api.test-utils :refer :all] |
| 3 | + [compojure.api.test-utils :as h] |
4 | 4 | [criterium.core :as cc] |
5 | 5 | [ring.util.http-response :refer :all] |
6 | | - [schema.core :as s])) |
| 6 | + [schema.core :as s] |
| 7 | + [clojure.java.io :as io] |
| 8 | + [cheshire.core :as json])) |
7 | 9 |
|
8 | 10 | ;; |
9 | 11 | ;; start repl with `lein perf repl` |
10 | 12 | ;; perf measured with the following setup: |
11 | 13 | ;; |
12 | | -;; Model Name: MacBook Pro |
13 | | -;; Model Identifier: MacBookPro11,3 |
14 | | -;; Processor Name: Intel Core i7 |
15 | | -;; Processor Speed: 2,5 GHz |
16 | | -;; Number of Processors: 1 |
17 | | -;; Total Number of Cores: 4 |
18 | | -;; L2 Cache (per Core): 256 KB |
19 | | -;; L3 Cache: 6 MB |
20 | | -;; Memory: 16 GB |
| 14 | +;; Model Name: MacBook Pro |
| 15 | +;; Model Identifier: MacBookPro11,3 |
| 16 | +;; Processor Name: Intel Core i7 |
| 17 | +;; Processor Speed: 2,5 GHz |
| 18 | +;; Number of Processors: 1 |
| 19 | +;; Total Number of Cores: 4 |
| 20 | +;; L2 Cache (per Core): 256 KB |
| 21 | +;; L3 Cache: 6 MB |
| 22 | +;; Memory: 16 GB |
21 | 23 | ;; |
22 | 24 |
|
23 | 25 | (defn title [s] |
|
28 | 30 | (apply str (repeat (+ 6 (count s)) "#")) |
29 | 31 | "\u001B[0m\n"))) |
30 | 32 |
|
| 33 | +(defn post* [app uri json] |
| 34 | + (-> |
| 35 | + (app {:uri uri |
| 36 | + :request-method :post |
| 37 | + :content-type "application/json" |
| 38 | + :body (io/input-stream (.getBytes json))}) |
| 39 | + :body |
| 40 | + slurp)) |
| 41 | + |
| 42 | +(defn parse [s] (json/parse-string s true)) |
| 43 | + |
31 | 44 | (s/defschema Order {:id s/Str |
32 | 45 | :name s/Str |
33 | 46 | (s/optional-key :description) s/Str |
|
39 | 52 |
|
40 | 53 | (defn bench [] |
41 | 54 |
|
42 | | - |
43 | 55 | (let [app (api |
44 | 56 | (GET* "/30" [] |
45 | 57 | (ok {:result 30}))) |
46 | | - call #(get* app "/30")] |
| 58 | + call #(h/get* app "/30")] |
47 | 59 |
|
48 | 60 | (title "GET JSON") |
49 | 61 |
|
50 | 62 | (assert (= {:result 30} (second (call)))) |
51 | 63 | (cc/bench (call))) |
52 | 64 |
|
53 | | - ; 26µs => 26µs (-0%) |
| 65 | + ; 27µs => 27µs (-0%) |
54 | 66 |
|
55 | 67 | (let [app (api |
56 | 68 | (POST* "/plus" [] |
57 | 69 | :return {:result s/Int} |
58 | 70 | :body-params [x :- s/Int, y :- s/Int] |
59 | 71 | (ok {:result (+ x y)}))) |
60 | | - data (json {:x 10, :y 20}) |
| 72 | + data (h/json {:x 10, :y 20}) |
61 | 73 | call #(post* app "/plus" data)] |
62 | 74 |
|
63 | 75 | (title "JSON POST with 2-way coercion") |
64 | 76 |
|
65 | | - (assert (= {:result 30} (second (call)))) |
| 77 | + (assert (= {:result 30} (parse (call)))) |
66 | 78 | (cc/bench (call))) |
67 | 79 |
|
68 | | - ;; 87µs => 65µs (-25%) |
| 80 | + ;; 73µs => 53µs (-27%) |
69 | 81 |
|
70 | 82 | (let [app (api |
71 | 83 | (context* "/a" [] |
|
75 | 87 | :return {:result s/Int} |
76 | 88 | :body-params [x :- s/Int, y :- s/Int] |
77 | 89 | (ok {:result (+ x y)})))))) |
78 | | - data (json {:x 10, :y 20}) |
| 90 | + data (h/json {:x 10, :y 20}) |
79 | 91 | call #(post* app "/a/b/c/plus" data)] |
80 | 92 |
|
81 | 93 | (title "JSON POST with 2-way coercion + contexts") |
82 | 94 |
|
83 | | - (assert (= {:result 30} (second (call)))) |
| 95 | + (assert (= {:result 30} (parse (call)))) |
84 | 96 | (cc/bench (call))) |
85 | 97 |
|
86 | | - ;; 102µs => 78µs (-24%) |
| 98 | + ;; 85µs => 67µs (-21%) |
87 | 99 |
|
88 | 100 | (let [app (api |
89 | 101 | (POST* "/echo" [] |
90 | 102 | :return Order |
91 | 103 | :body [order Order] |
92 | 104 | (ok order))) |
93 | | - data (json {:id "123" |
94 | | - :name "Tommi's order" |
95 | | - :description "Totally great order" |
96 | | - :address {:street "Randomstreet 123" |
97 | | - :country "FI"} |
98 | | - :orders [{:name "k1" |
99 | | - :price 123.0 |
100 | | - :shipping true} |
101 | | - {:name "k2" |
102 | | - :price 42.0 |
103 | | - :shipping false}]}) |
| 105 | + data (h/json {:id "123" |
| 106 | + :name "Tommi's order" |
| 107 | + :description "Totally great order" |
| 108 | + :address {:street "Randomstreet 123" |
| 109 | + :country "FI"} |
| 110 | + :orders [{:name "k1" |
| 111 | + :price 123.0 |
| 112 | + :shipping true} |
| 113 | + {:name "k2" |
| 114 | + :price 42.0 |
| 115 | + :shipping false}]}) |
104 | 116 | call #(post* app "/echo" data)] |
105 | 117 |
|
106 | 118 | (title "JSON POST with nested data") |
107 | 119 |
|
108 | | - (s/check Order (second (call))) |
| 120 | + (s/validate Order (parse (call))) |
109 | 121 | (cc/bench (call))) |
110 | 122 |
|
111 | | - ;; 311µs => 194µs (-38%) |
| 123 | + ;; 266µs => 156µs (-41%) |
112 | 124 |
|
113 | 125 | ) |
114 | 126 |
|
|
0 commit comments