rack-jet_router 1.1.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/bench/bench.rb ADDED
@@ -0,0 +1,367 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ ##
5
+ ## Usage:
6
+ ## $ gem install bundler
7
+ ## $ bundler install
8
+ ## $ ruby bench.rb --N=1000_000
9
+ ## $ ruby bench.rb --N=1000_000 --rack=0 --sinatra=0 --multiplexer=0 # --hanami=0 --jetrouter=0 --keight=0
10
+ ##
11
+
12
+
13
+ $LOAD_PATH << File.absolute_path("../../lib", __FILE__)
14
+
15
+ require 'benchmarker'
16
+ Benchmarker.parse_cmdopts()
17
+
18
+ require 'rack' rescue nil unless '0' == $opt_rack
19
+ require 'rack/jet_router' rescue nil unless '0' == $opt_jetrouter
20
+ require 'rack/multiplexer' rescue nil unless '0' == $opt_multiplexer
21
+ require 'sinatra/base' rescue nil unless '0' == $opt_sinatra
22
+ require 'keight' rescue nil unless '0' == $opt_keight
23
+ require 'hanami/router' rescue nil unless '0' == $opt_hanami
24
+
25
+ flag_rack = defined?(Rack) && $opt_rack != '0'
26
+ flag_jetrouter = defined?(Rack::JetRouter)
27
+ flag_multiplexer = defined?(Rack::Multiplexer)
28
+ flag_sinatra = defined?(Sinatra)
29
+ flag_keight = defined?(K8)
30
+ flag_hanami = defined?(Hanami::Router)
31
+
32
+ def version_info(name, opt, flag)
33
+ version = opt == '0' ? "(skipped)" \
34
+ : ! flag ? "(not installed)" \
35
+ : yield
36
+ return "** %-20s : %s" % [name, version]
37
+ end
38
+
39
+ puts version_info("rack" , $opt_rack , flag_rack ) { Rack.release }
40
+ puts version_info("rack-jet_router" , $opt_jetrouter , flag_jetrouter ) { Rack::JetRouter::RELEASE }
41
+ puts version_info("rack-multiplexer", $opt_multiplexer, flag_multiplexer) { Rack::Multiplexer::VERSION }
42
+ puts version_info("sinatra" , $opt_sinatra , flag_sinatra ) { Sinatra::VERSION }
43
+ puts version_info("keight" , $opt_keight , flag_keight ) { K8::RELEASE }
44
+ puts version_info("hanami-router" , $opt_hanami , flag_hanami ) { Hanami::Router::VERSION }
45
+
46
+
47
+ ENTRIES = ('a'..'z').map.with_index {|x, i| "%s%02d" % [x*3, i+1] }
48
+
49
+ #flag_sinatra = false # because too slow
50
+ target_urlpaths = [
51
+ "/api/aaa01",
52
+ "/api/aaa01/123",
53
+ # "/api/aaa01/123/comments/7",
54
+ "/api/zzz26",
55
+ "/api/zzz26/456",
56
+ # "/api/zzz26/456/comments/7",
57
+ ]
58
+
59
+
60
+ if flag_rack
61
+
62
+ rack_app1 = proc do |env|
63
+ [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
64
+ end
65
+
66
+ rack_app4 = proc do |env; req, resp|
67
+ req = Rack::Request.new(env)
68
+ resp = Rack::Response.new
69
+ #[resp.status, resp.headers, ["<h1>hello</h1>"]]
70
+ #[200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
71
+ resp.status = 200
72
+ resp.headers["Content-Type"] = "text/html"
73
+ resp.write("<h1>hello</h1>")
74
+ resp.finish()
75
+ end
76
+
77
+ end
78
+
79
+
80
+ if flag_jetrouter
81
+
82
+ jet_router = proc {
83
+ handler1 = proc {|env|
84
+ [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
85
+ }
86
+ handler2 = proc {|env|
87
+ d = env['rack.urlpath_params']
88
+ [200, {"Content-Type"=>"text/html"}, ["<h1>id=#{d['id']}</h1>"]]
89
+ }
90
+ handler3 = proc {|env|
91
+ d = env['rack.urlpath_params']
92
+ [200, {"Content-Type"=>"text/html"}, ["<h1>id=#{d['id']}, comment_id=#{d['comment_id']}</h1>"]]
93
+ }
94
+ mapping = [
95
+ ['/api', ENTRIES.each_with_object([]) {|x, arr|
96
+ arr << ["/#{x}", [
97
+ ['', handler1],
98
+ ['/:id', handler2],
99
+ ]]
100
+ arr << ["/#{x}/:id/comments", [
101
+ ['/:comment_id', handler3],
102
+ ]]
103
+ },
104
+ ],
105
+ ]
106
+ opts = {
107
+ cache_size: ($opt_k8cache || 0).to_i,
108
+ _enable_range: $opt_k8range != '0',
109
+ #prefix_minlength_target: /\A\/api\/\w/,
110
+ }
111
+ Rack::JetRouter.new(mapping, **opts)
112
+ }.call()
113
+
114
+ end
115
+
116
+
117
+ if flag_multiplexer
118
+
119
+ mpx_app = Rack::Multiplexer.new().tap do |app|
120
+ handler1 = proc {|env|
121
+ [200, {"Content-Type"=>"text/html"}, ["<h1>hello</h1>"]]
122
+ }
123
+ handler2 = proc {|env|
124
+ d = env['rack.request.query_hash']
125
+ [200, {"Content-Type"=>"text/html"}, ["<h1>id=#{d['id']}</h1>"]]
126
+ }
127
+ handler3 = proc {|env|
128
+ d = env['rack.request.query_hash']
129
+ [200, {"Content-Type"=>"text/html"}, ["<h1>id=#{d['id']}, comment_id=#{d['comment_id']}</h1>"]]
130
+ }
131
+ ENTRIES.each do |x|
132
+ app.get "/api/#{x}" , handler1
133
+ app.get "/api/#{x}/:id" , handler2
134
+ app.get "/api/#{x}/:id/comments/:comment_id" , handler3
135
+ end
136
+ end
137
+
138
+ end
139
+
140
+
141
+ if flag_sinatra
142
+
143
+ class SinaApp < Sinatra::Base
144
+ ## run benchmarks without middlewares
145
+ set :sessions , false
146
+ set :logging , false
147
+ set :protection , false
148
+ set :x_cascade , false
149
+ #
150
+ ENTRIES.each do |x|
151
+ get "/api/#{x}" do "<h1>hello</h1>" end
152
+ get "/api/#{x}/:id" do "<h1>id=#{params['id']}</h1>" end
153
+ get "/api/#{x}/:id/comments/:comment_id" do "<h1>id=#{params['id']}, comment_id=#{params['comment_id']}</h1>" end
154
+ end
155
+ end
156
+
157
+ sina_app = SinaApp.new
158
+
159
+ end
160
+
161
+
162
+ if flag_keight
163
+
164
+ class K8HelloAction < K8::Action
165
+ mapping '', :GET=>:do_index
166
+ mapping '/{id}', :GET=>:do_show
167
+ def do_index ; "<h1>hello</h1>"; end
168
+ def do_show(id) ; "<h1>id=#{id.inspect}</h1>"; end
169
+ end
170
+
171
+ class K8CommentAction < K8::Action
172
+ mapping '/{comment_id}', :GET=>:do_show
173
+ def do_show(id, comment_id); "<h1>id=#{id}, comment_id=#{comment_id}</h1>"; end
174
+ end
175
+
176
+ k8_app = (proc {
177
+ mapping = [
178
+ ["/api", ENTRIES.each_with_object([]) {|x, arr|
179
+ arr << ["/#{x}" , K8HelloAction]
180
+ arr << ["/#{x}/{id}/comments", K8CommentAction]
181
+ }
182
+ ],
183
+ ]
184
+ opts = {
185
+ #urlpath_cache_size: 0,
186
+ }
187
+ K8::RackApplication.new(mapping, **opts)
188
+ }).call()
189
+
190
+ #k8_app.find('/api/books') # warm up
191
+
192
+ end
193
+
194
+
195
+ if flag_hanami
196
+
197
+ ## ref: https://github.com/hanami/router
198
+ hanami_app = Hanami::Router.new do
199
+ index_handler = proc do |env|
200
+ [200, {"Content-Type": "text/html"}, ["<h1>hello</h1>"]]
201
+ end
202
+ show_handler = proc do |env|
203
+ d = env['router.params']
204
+ [200, {"Content-Type": "text/html"}, ["<h1>id=#{d[:id]}</h1>"]]
205
+ end
206
+ comment_handler = proc do |env|
207
+ d = env['router.params']
208
+ [200, {"Content-Type": "text/html"}, ["<h1>id=#{d[:id]}, comment_id=#{d[:comment_id]}</h1>"]]
209
+ end
210
+ #
211
+ scope "api" do
212
+ ENTRIES.each do |x|
213
+ get "/#{x}" , to: index_handler
214
+ get "/#{x}/:id", to: show_handler
215
+ get "/#{x}/:id/comments/:comment_id", to: comment_handler
216
+ end
217
+ end
218
+ end
219
+
220
+ end
221
+
222
+
223
+ begin
224
+ Rack::MockRequest
225
+ rescue
226
+ require 'rack'
227
+ end
228
+ $environ = Rack::MockRequest.env_for("http://localhost/", method: 'GET')
229
+ $environ.freeze
230
+
231
+ def newenv(path)
232
+ env = $environ.dup
233
+ env['PATH_INFO'] = path
234
+ env
235
+ end
236
+
237
+
238
+ N = ($opt_N || 100000).to_i
239
+ title = "Router library benchmark"
240
+ Benchmarker.scope(title, width: 33, loop: 1, iter: 1, extra: 0, sleep: 0) do
241
+
242
+ puts "** N=#{N}"
243
+ puts ""
244
+
245
+ ### empty task
246
+ task nil do
247
+ i = 0; n = N
248
+ while (i += 1) <= n
249
+ #newenv("/api")
250
+ end
251
+ end
252
+
253
+ ### Rack
254
+ if flag_rack
255
+ #target_urlpaths.each do |x|
256
+ # rack_app1.call(newenv(x)) # warm up
257
+ # task "(Rack plain app) #{x}" do # no routing
258
+ # env = newenv(x)
259
+ # i = 0; n = N
260
+ # while (i += 1) <= n
261
+ # tuple = rack_app1.call(env)
262
+ # end
263
+ # tuple
264
+ # end
265
+ #end
266
+ target_urlpaths.each do |x|
267
+ rack_app4.call(newenv(x)) # warm up
268
+ task "(Rack::Req+Res) #{x}" do # no routing
269
+ env = newenv(x)
270
+ i = 0; n = N
271
+ while (i += 1) <= n
272
+ tuple = rack_app4.call(env)
273
+ end
274
+ tuple
275
+ end
276
+ end
277
+ end
278
+
279
+ ### Rack::JetRouter
280
+ if flag_jetrouter
281
+ target_urlpaths.each do |x|
282
+ jet_router.call(newenv(x)) # warm up
283
+ task "(JetRouter) #{x}" do
284
+ env = newenv(x)
285
+ i = 0; n = N
286
+ while (i += 1) <= n
287
+ tuple = jet_router.call(env)
288
+ end
289
+ tuple
290
+ end
291
+ end
292
+ end
293
+
294
+ ### Rack::Multiplexer
295
+ if flag_multiplexer
296
+ target_urlpaths.each do |x|
297
+ mpx_app.call(newenv(x)) # warm up
298
+ task "(Multiplexer) #{x}" do
299
+ env = newenv(x)
300
+ i = 0; n = N
301
+ while (i += 1) <= n
302
+ tuple = mpx_app.call(env)
303
+ end
304
+ tuple
305
+ end
306
+ end
307
+ end
308
+
309
+ ### Sinatra
310
+ if flag_sinatra
311
+ target_urlpaths.each do |x|
312
+ sina_app.call(newenv(x)) # warm up
313
+ task "(Sinatra) #{x}" do
314
+ env = newenv(x)
315
+ i = 0; n = N
316
+ while (i += 1) <= n
317
+ tuple = sina_app.call(env)
318
+ end
319
+ tuple
320
+ end
321
+ end
322
+ end
323
+
324
+ ### Keight
325
+ if flag_keight
326
+ target_urlpaths.each do |x|
327
+ k8_app.call(newenv(x)) # warm up
328
+ task "(Keight) #{x}" do
329
+ env = newenv(x)
330
+ i = 0; n = N
331
+ while (i += 1) <= n
332
+ tuple = k8_app.call(env)
333
+ end
334
+ tuple
335
+ end
336
+ end
337
+ end
338
+
339
+ ### Hanami
340
+ if flag_hanami
341
+ target_urlpaths.each do |x|
342
+ hanami_app.call(newenv(x)) # warm up
343
+ task "(Hanami::Router) #{x}" do
344
+ env = newenv(x)
345
+ i = 0; n = N
346
+ while (i += 1) <= n
347
+ tuple = hanami_app.call(env)
348
+ end
349
+ tuple
350
+ end
351
+ end
352
+ end
353
+
354
+ ## validation
355
+ validate do |val| # or: validate do |val, task_name, tag|
356
+ tuple = val
357
+ assert tuple[0] == 200, "200 expected but got #{tuple[0]}"
358
+ body = tuple[2].each {|x| break x }
359
+ assert body == "<h1>hello</h1>" || \
360
+ body == "<h1>id=123</h1>" || \
361
+ body == "<h1>id=456</h1>" || \
362
+ body == "<h1>id=123, comment_id=7</h1>" || \
363
+ body == "<h1>id=456, comment_id=7</h1>", \
364
+ "#{body.inspect}: unpexpected body"
365
+ end
366
+
367
+ end