keight 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +263 -0
- data/Rakefile +92 -0
- data/bench/bench.rb +278 -0
- data/bench/benchmarker.rb +502 -0
- data/bin/k8rb +496 -0
- data/keight.gemspec +36 -0
- data/lib/keight/skeleton/.gitignore +10 -0
- data/lib/keight/skeleton/app/action.rb +98 -0
- data/lib/keight/skeleton/app/api/hello.rb +39 -0
- data/lib/keight/skeleton/app/form/.keep +0 -0
- data/lib/keight/skeleton/app/helper/.keep +0 -0
- data/lib/keight/skeleton/app/model/.keep +0 -0
- data/lib/keight/skeleton/app/model.rb +144 -0
- data/lib/keight/skeleton/app/page/welcome.rb +17 -0
- data/lib/keight/skeleton/app/template/_layout.html.eruby +56 -0
- data/lib/keight/skeleton/app/template/welcome.html.eruby +6 -0
- data/lib/keight/skeleton/app/usecase/.keep +0 -0
- data/lib/keight/skeleton/config/app.rb +29 -0
- data/lib/keight/skeleton/config/app_dev.private +11 -0
- data/lib/keight/skeleton/config/app_dev.rb +8 -0
- data/lib/keight/skeleton/config/app_prod.rb +7 -0
- data/lib/keight/skeleton/config/app_stg.rb +5 -0
- data/lib/keight/skeleton/config/app_test.private +11 -0
- data/lib/keight/skeleton/config/app_test.rb +8 -0
- data/lib/keight/skeleton/config/server_puma.rb +22 -0
- data/lib/keight/skeleton/config/server_unicorn.rb +21 -0
- data/lib/keight/skeleton/config/urlpath_mapping.rb +16 -0
- data/lib/keight/skeleton/config.rb +44 -0
- data/lib/keight/skeleton/config.ru +21 -0
- data/lib/keight/skeleton/index.txt +38 -0
- data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js +6 -0
- data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js.gz +0 -0
- data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js +4 -0
- data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js.gz +0 -0
- data/lib/keight/skeleton/tmp/upload/.keep +0 -0
- data/lib/keight.rb +2017 -0
- data/test/data/example1.jpg +0 -0
- data/test/data/example1.png +0 -0
- data/test/data/multipart.form +0 -0
- data/test/data/wabisabi.js +77 -0
- data/test/data/wabisabi.js.gz +0 -0
- data/test/keight_test.rb +3161 -0
- data/test/oktest.rb +1537 -0
- metadata +114 -0
@@ -0,0 +1,502 @@
|
|
1
|
+
###
|
2
|
+
### $Release: 0.0.1 $
|
3
|
+
### $Copyright: copyright(c) 2014-2015 kuwata-lab.com all rights reserved $
|
4
|
+
### $License: MIT License $
|
5
|
+
###
|
6
|
+
|
7
|
+
|
8
|
+
module Benchmarker
|
9
|
+
|
10
|
+
VERSION = "$Release: 0.0.1 $".split(/ /)[1]
|
11
|
+
|
12
|
+
def self.new(opts={}, &block)
|
13
|
+
#: creates runner object and returns it.
|
14
|
+
runner = RUNNER.new(opts)
|
15
|
+
if block
|
16
|
+
runner._before_all()
|
17
|
+
runner._run(&block)
|
18
|
+
runner._after_all()
|
19
|
+
end
|
20
|
+
runner
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.bm(width=30, &block) # for compatibility with benchmark.rb
|
24
|
+
return self.new(:width=>30, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.platform()
|
28
|
+
#: returns platform information.
|
29
|
+
return <<END
|
30
|
+
benchmarker.rb: release #{VERSION}
|
31
|
+
RUBY_VERSION: #{RUBY_VERSION}
|
32
|
+
RUBY_PATCHLEVEL: #{RUBY_PATCHLEVEL}
|
33
|
+
RUBY_PLATFORM: #{RUBY_PLATFORM}
|
34
|
+
END
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
class Runner
|
39
|
+
|
40
|
+
def initialize(opts={})
|
41
|
+
#: takes :loop, :cycle, and :extra options.
|
42
|
+
@loop = opts[:loop]
|
43
|
+
@cycle = opts[:cycle]
|
44
|
+
@extra = opts[:extra]
|
45
|
+
#:
|
46
|
+
@tasks = []
|
47
|
+
@report = REPORTER.new(opts)
|
48
|
+
@stats = STATS.new(@report, opts)
|
49
|
+
@_section_title = ""
|
50
|
+
@_section_started = false
|
51
|
+
end
|
52
|
+
|
53
|
+
attr_accessor :tasks, :report, :stats
|
54
|
+
|
55
|
+
def task(label, opts={}, &block)
|
56
|
+
#: prints section title if not printed yet.
|
57
|
+
#: creates task objet and returns it.
|
58
|
+
#: runs task when :skip option is not specified.
|
59
|
+
#: skip block and prints message when :skip option is specified.
|
60
|
+
#: subtracts times of empty task if exists.
|
61
|
+
skip_message = opts[:skip]
|
62
|
+
t = _new_task(label, skip_message, &block)
|
63
|
+
#: saves created task object unless :skip optin is not specified.
|
64
|
+
@tasks << t unless skip_message
|
65
|
+
t
|
66
|
+
end
|
67
|
+
|
68
|
+
alias report task # for compatibility with benchmark.rb
|
69
|
+
|
70
|
+
def empty_task(label="(Empty)", &block)
|
71
|
+
#:: clear @_empty_task.
|
72
|
+
@_empty_task = nil
|
73
|
+
#: prints section title if not printed yet.
|
74
|
+
#: creates empty task object and returns it.
|
75
|
+
t = _new_task(label, &block)
|
76
|
+
#: saves empty task object.
|
77
|
+
#:: don't add empty task to @tasks.
|
78
|
+
@_empty_task = t
|
79
|
+
t
|
80
|
+
end
|
81
|
+
|
82
|
+
#--
|
83
|
+
#def skip_task(label, message=" ** skipped **")
|
84
|
+
# #: prints section title if not printed yet.
|
85
|
+
# t = _new_task(label)
|
86
|
+
# #: prints task label and message instead of times.
|
87
|
+
# @report.write(message + "\n")
|
88
|
+
# #: don't change @tasks.
|
89
|
+
#end
|
90
|
+
#++
|
91
|
+
|
92
|
+
def _before_all # :nodoc:
|
93
|
+
#: prints Benchmarker.platform().
|
94
|
+
print Benchmarker.platform()
|
95
|
+
end
|
96
|
+
|
97
|
+
def _after_all # :nodoc:
|
98
|
+
#: prints statistics out benchmarks.
|
99
|
+
@stats.all(@tasks)
|
100
|
+
end
|
101
|
+
|
102
|
+
def _run # :nodoc:
|
103
|
+
#: when @cycle > 1...
|
104
|
+
if @cycle && @cycle > 1
|
105
|
+
@all_tasks = []
|
106
|
+
#: prints output of cycle into stderr.
|
107
|
+
@report._switch_out_to_err do
|
108
|
+
#: yields block @cycle times when @extra is not specified.
|
109
|
+
#: yields block @cycle + 2*@extra times when @extra is specified.
|
110
|
+
i = 0
|
111
|
+
cycle = @cycle
|
112
|
+
cycle += 2 * @extra if @extra
|
113
|
+
cycle.times do
|
114
|
+
_reset_section("(##{i+=1})")
|
115
|
+
@all_tasks << (@tasks = [])
|
116
|
+
#: yields block with self as block paramter.
|
117
|
+
yield self
|
118
|
+
end
|
119
|
+
end
|
120
|
+
#: reports average of results.
|
121
|
+
@tasks = _calc_averages(@all_tasks, @extra)
|
122
|
+
_report_average_section(@tasks)
|
123
|
+
#: when @cycle == 0 or not specified...
|
124
|
+
else
|
125
|
+
#: yields block only once.
|
126
|
+
_reset_section("")
|
127
|
+
#: yields block with self as block paramter.
|
128
|
+
yield self
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def _reset_section(section_title)
|
135
|
+
@_section_started = false
|
136
|
+
@_section_title = section_title
|
137
|
+
end
|
138
|
+
|
139
|
+
def _new_task(label, skip_message=nil, &block)
|
140
|
+
#: prints section title if not printed yet.
|
141
|
+
_report_section_title_if_not_printed_yet()
|
142
|
+
#: creates task objet and returns it.
|
143
|
+
t = TASK.new(label, @loop)
|
144
|
+
@report.task_label(label)
|
145
|
+
#: skip block and prints message when :skip option is specified.
|
146
|
+
if skip_message
|
147
|
+
@report.write(skip_message + "\n")
|
148
|
+
#: runs task when :skip option is not specified.
|
149
|
+
elsif block
|
150
|
+
t.run(&block)
|
151
|
+
#: subtracts times of empty task if exists.
|
152
|
+
t.sub(@_empty_task) if @_empty_task
|
153
|
+
@report.task_times(t.user, t.sys, t.total, t.real)
|
154
|
+
end
|
155
|
+
t
|
156
|
+
end
|
157
|
+
|
158
|
+
def _report_section_title_if_not_printed_yet
|
159
|
+
if ! @_section_started
|
160
|
+
@_section_started = true
|
161
|
+
@report.section_title(@_section_title)\
|
162
|
+
.section_headers("user", "sys", "total", "real")
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def _calc_averages(all_tasks, extra)
|
167
|
+
#: calculates average times of tasks.
|
168
|
+
tasks_list = _transform_all_tasks(all_tasks)
|
169
|
+
if extra
|
170
|
+
@report.section_title("Remove Min & Max").section_headers("min", "cycle", "max", "cycle")
|
171
|
+
tasks_list = tasks_list.collect {|tasks| _remove_min_max(tasks, extra) }
|
172
|
+
end
|
173
|
+
avg_tasks = tasks_list.collect {|tasks| Task.average(tasks) }
|
174
|
+
avg_tasks
|
175
|
+
end
|
176
|
+
|
177
|
+
def _transform_all_tasks(all_tasks)
|
178
|
+
tasks_list = []
|
179
|
+
all_tasks.each do |tasks|
|
180
|
+
tasks.each_with_index do |task, i|
|
181
|
+
(tasks_list[i] ||= []) << task
|
182
|
+
end
|
183
|
+
end
|
184
|
+
tasks_list
|
185
|
+
end
|
186
|
+
|
187
|
+
def _remove_min_max(tasks, extra)
|
188
|
+
#: reports min and max tasks.
|
189
|
+
idx = -1
|
190
|
+
pairs = tasks.collect {|task| [task, idx+=1] }
|
191
|
+
pairs = pairs.sort_by {|task, idx| task.real } # 1.8 doesn't support sort_by!
|
192
|
+
j = -1
|
193
|
+
while (j += 1) < extra
|
194
|
+
@report.task_label(j == 0 ? pairs[j].first.label : '')
|
195
|
+
task, idx = pairs[j] # min
|
196
|
+
@report.task_time(task.real).task_index(idx+1)
|
197
|
+
task, idx = pairs[-j-1] # max
|
198
|
+
@report.task_time(task.real).task_index(idx+1)
|
199
|
+
@report.text("\n")
|
200
|
+
end
|
201
|
+
#: removes min and max tasks, and returns remained tasks.
|
202
|
+
remained_tasks = pairs[extra...-extra].collect {|task, idx| task }
|
203
|
+
remained_tasks
|
204
|
+
end
|
205
|
+
|
206
|
+
def _report_average_section(tasks)
|
207
|
+
title = _get_average_section_title()
|
208
|
+
@report.section_title(title).section_headers("user", "sys", "total", "real")
|
209
|
+
tasks.each do |t|
|
210
|
+
@report.task_label(t.label).task_times(t.user, t.sys, t.total, t.real)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
def _get_average_section_title()
|
215
|
+
#: returns 'Average of N (=x-2*y)' string if label width is enough wide.
|
216
|
+
#: returns 'Average of N' string if label width is not enough wide.
|
217
|
+
title = "Average of #{@cycle}"
|
218
|
+
if @extra
|
219
|
+
s = " (=#{@cycle+2*@extra}-2*#{@extra})"
|
220
|
+
title << s if "## #{title}#{s}".length <= @report.label_width
|
221
|
+
end
|
222
|
+
title
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
RUNNER = Runner
|
228
|
+
|
229
|
+
|
230
|
+
class Task
|
231
|
+
|
232
|
+
def initialize(label, loop=1, &block)
|
233
|
+
#: takes label and loop.
|
234
|
+
@label = label
|
235
|
+
@loop = loop
|
236
|
+
#: sets all times to zero.
|
237
|
+
@user = @sys = @total = @real = 0.0
|
238
|
+
end
|
239
|
+
|
240
|
+
attr_accessor :label, :loop, :user, :sys, :total, :real
|
241
|
+
|
242
|
+
def run
|
243
|
+
#: yields block for @loop times.
|
244
|
+
ntimes = @loop || 1
|
245
|
+
pt1 = Process.times
|
246
|
+
t1 = Time.now
|
247
|
+
if ntimes > 1
|
248
|
+
ntimes.times { yield }
|
249
|
+
else
|
250
|
+
yield
|
251
|
+
end
|
252
|
+
pt2 = Process.times
|
253
|
+
t2 = Time.now
|
254
|
+
#: measures times.
|
255
|
+
@user = pt2.utime - pt1.utime
|
256
|
+
@sys = pt2.stime - pt1.stime
|
257
|
+
@total = @user + @sys
|
258
|
+
@real = t2 - t1
|
259
|
+
return self
|
260
|
+
end
|
261
|
+
|
262
|
+
def add(other)
|
263
|
+
#: adds other's times into self.
|
264
|
+
@user += other.user
|
265
|
+
@sys += other.sys
|
266
|
+
@total += other.total
|
267
|
+
@real += other.real
|
268
|
+
#: returns self.
|
269
|
+
return self
|
270
|
+
end
|
271
|
+
|
272
|
+
def sub(other)
|
273
|
+
#: substracts other's times from self.
|
274
|
+
@user -= other.user
|
275
|
+
@sys -= other.sys
|
276
|
+
@total -= other.total
|
277
|
+
@real -= other.real
|
278
|
+
#: returns self.
|
279
|
+
return self
|
280
|
+
end
|
281
|
+
|
282
|
+
def mul(n)
|
283
|
+
#: multiplies times with n.
|
284
|
+
@user *= n
|
285
|
+
@sys *= n
|
286
|
+
@total *= n
|
287
|
+
@real *= n
|
288
|
+
#: returns self.
|
289
|
+
return self
|
290
|
+
end
|
291
|
+
|
292
|
+
def div(n)
|
293
|
+
#: divides times by n.
|
294
|
+
@user /= n
|
295
|
+
@sys /= n
|
296
|
+
@total /= n
|
297
|
+
@real /= n
|
298
|
+
#: returns self.
|
299
|
+
return self
|
300
|
+
end
|
301
|
+
|
302
|
+
def self.average(tasks)
|
303
|
+
#: returns empty task when argument is empty.
|
304
|
+
n = tasks.length
|
305
|
+
return self.new(nil) if n == 0
|
306
|
+
#: create new task with label.
|
307
|
+
task = self.new(tasks.first.label)
|
308
|
+
#: returns averaged task.
|
309
|
+
tasks.each {|t| task.add(t) }
|
310
|
+
task.div(n)
|
311
|
+
return task
|
312
|
+
end
|
313
|
+
|
314
|
+
end
|
315
|
+
|
316
|
+
TASK = Task
|
317
|
+
|
318
|
+
|
319
|
+
class Reporter
|
320
|
+
|
321
|
+
def initialize(opts={})
|
322
|
+
#: takes :out, :err, :width, and :format options.
|
323
|
+
@out = opts[:out] || $stdout
|
324
|
+
@err = opts[:err] || $stderr
|
325
|
+
self.label_width = opts[:width] || 30
|
326
|
+
self.format_time = opts[:format] || "%9.4f"
|
327
|
+
end
|
328
|
+
|
329
|
+
attr_accessor :out, :err
|
330
|
+
attr_reader :label_width, :format_time
|
331
|
+
|
332
|
+
def _switch_out_to_err() # :nodoc:
|
333
|
+
#: switches @out to @err temporarily.
|
334
|
+
begin
|
335
|
+
out = @out
|
336
|
+
@out = @err
|
337
|
+
yield
|
338
|
+
ensure
|
339
|
+
@out = out
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def label_width=(width)
|
344
|
+
#: sets @label_width.
|
345
|
+
@label_width = width
|
346
|
+
#: sets @format_label, too.
|
347
|
+
@format_label = "%-#{width}s"
|
348
|
+
end
|
349
|
+
|
350
|
+
def format_time=(format)
|
351
|
+
#: sets @format_time.
|
352
|
+
@format_time = format
|
353
|
+
#: sets @format_header, too.
|
354
|
+
m = /%-?(\d+)\.\d+/.match(format)
|
355
|
+
@format_header = "%#{$1.to_i}s" if m
|
356
|
+
end
|
357
|
+
|
358
|
+
def write(*args)
|
359
|
+
#: writes arguments to @out with '<<' operator.
|
360
|
+
args.each {|x| @out << x.to_s }
|
361
|
+
#: saves the last argument.
|
362
|
+
@_prev = args[-1]
|
363
|
+
#: returns self.
|
364
|
+
return self
|
365
|
+
end
|
366
|
+
alias text write
|
367
|
+
|
368
|
+
def report_section_title(title)
|
369
|
+
#: prints newline at first.
|
370
|
+
write "\n"
|
371
|
+
#: prints section title with @format_label.
|
372
|
+
write @format_label % "## #{title}"
|
373
|
+
#: returns self.
|
374
|
+
return self
|
375
|
+
end
|
376
|
+
alias section_title report_section_title
|
377
|
+
|
378
|
+
def report_section_headers(*headers)
|
379
|
+
#: prints headers.
|
380
|
+
headers.each do |header|
|
381
|
+
report_section_header(header)
|
382
|
+
end
|
383
|
+
#: prints newline at end.
|
384
|
+
write "\n"
|
385
|
+
#: returns self.
|
386
|
+
return self
|
387
|
+
end
|
388
|
+
alias section_headers report_section_headers
|
389
|
+
|
390
|
+
def report_section_header(header)
|
391
|
+
#: prints header with @format_header.
|
392
|
+
write " ", @format_header % header
|
393
|
+
#: returns self.
|
394
|
+
return self
|
395
|
+
end
|
396
|
+
alias section_header report_section_header
|
397
|
+
|
398
|
+
def report_task_label(label)
|
399
|
+
#: prints task label with @format_label.
|
400
|
+
write @format_label % label
|
401
|
+
#: returns self.
|
402
|
+
return self
|
403
|
+
end
|
404
|
+
alias task_label report_task_label
|
405
|
+
|
406
|
+
def report_task_times(user, sys, total, real)
|
407
|
+
#: prints task times with @format_time.
|
408
|
+
fmt = @format_time
|
409
|
+
write " ", fmt % user, " ", fmt % sys, " ", fmt % total, " ", fmt % real, "\n"
|
410
|
+
#: returns self.
|
411
|
+
return self
|
412
|
+
end
|
413
|
+
alias task_times report_task_times
|
414
|
+
|
415
|
+
def report_task_time(time)
|
416
|
+
#: prints task time with @format_titme.
|
417
|
+
write " ", @format_time % time
|
418
|
+
#: returns self.
|
419
|
+
return self
|
420
|
+
end
|
421
|
+
alias task_time report_task_time
|
422
|
+
|
423
|
+
def report_task_index(index)
|
424
|
+
#: prints task time with @format_titme.
|
425
|
+
write " ", @format_header % "(##{index})"
|
426
|
+
#: returns self.
|
427
|
+
return self
|
428
|
+
end
|
429
|
+
alias task_index report_task_index
|
430
|
+
|
431
|
+
end
|
432
|
+
|
433
|
+
REPORTER = Reporter
|
434
|
+
|
435
|
+
|
436
|
+
class Stats
|
437
|
+
|
438
|
+
def initialize(reporter, opts={})
|
439
|
+
#: takes reporter object.
|
440
|
+
@report = reporter
|
441
|
+
@key = opts[:key] || 'real'
|
442
|
+
@sort_key = opts[:sort_key] || 'real'
|
443
|
+
@loop = opts[:loop]
|
444
|
+
@numerator = opts[:numerator]
|
445
|
+
end
|
446
|
+
|
447
|
+
def all(tasks)
|
448
|
+
ranking(tasks)
|
449
|
+
ratio_matrix(tasks)
|
450
|
+
end
|
451
|
+
|
452
|
+
def ranking(tasks)
|
453
|
+
tasks = tasks.sort_by {|t| t.__send__(@sort_key) } if @sort_key
|
454
|
+
#: prints ranking.
|
455
|
+
key = @key
|
456
|
+
@report.section_title("Ranking").section_headers(key.to_s)
|
457
|
+
#base = tasks.min_by {|t| t.__send__(key) }.__send__(key) # min_by() is available since 1.8.7
|
458
|
+
base = tasks.collect {|t| t.__send__(key) }.min
|
459
|
+
tasks.each do |task|
|
460
|
+
sec = task.__send__(key).to_f
|
461
|
+
val = 100.0 * base / sec
|
462
|
+
@report.task_label(task.label).task_time(sec).text(" (%5.1f%%) " % val)
|
463
|
+
#: prints barchart if @numerator is not specified.
|
464
|
+
if ! @numerator
|
465
|
+
bar = '*' * (val / 5.0).round
|
466
|
+
@report.text(bar).text("\n")
|
467
|
+
#: prints inverse number if @numerator specified.
|
468
|
+
else
|
469
|
+
@report.text("%12.2f per sec" % (@numerator/ sec)).text("\n")
|
470
|
+
end
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
def ratio_matrix(tasks)
|
475
|
+
tasks = tasks.sort_by {|t| t.__send__(@sort_key) } if @sort_key
|
476
|
+
#: prints matrix.
|
477
|
+
key = @key
|
478
|
+
@report.section_title("Matrix").section_header("real")
|
479
|
+
tasks.each_with_index do |t, i|
|
480
|
+
@report.text(" %8s" % ("[%02d]" % (i+1)))
|
481
|
+
end
|
482
|
+
@report.text("\n")
|
483
|
+
i = 0
|
484
|
+
tasks.each do |base_task|
|
485
|
+
i += 1
|
486
|
+
base = base_task.__send__(key).to_f
|
487
|
+
@report.task_label("[%02d] %s" % [i, base_task.label]).task_time(base)
|
488
|
+
tasks.each do |t|
|
489
|
+
sec = t.__send__(key).to_f
|
490
|
+
val = 100.0 * sec / base
|
491
|
+
@report.text(" %7.1f%%" % val)
|
492
|
+
end
|
493
|
+
@report.text("\n")
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
end
|
498
|
+
|
499
|
+
STATS = Stats
|
500
|
+
|
501
|
+
|
502
|
+
end
|