keight 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +263 -0
  4. data/Rakefile +92 -0
  5. data/bench/bench.rb +278 -0
  6. data/bench/benchmarker.rb +502 -0
  7. data/bin/k8rb +496 -0
  8. data/keight.gemspec +36 -0
  9. data/lib/keight/skeleton/.gitignore +10 -0
  10. data/lib/keight/skeleton/app/action.rb +98 -0
  11. data/lib/keight/skeleton/app/api/hello.rb +39 -0
  12. data/lib/keight/skeleton/app/form/.keep +0 -0
  13. data/lib/keight/skeleton/app/helper/.keep +0 -0
  14. data/lib/keight/skeleton/app/model/.keep +0 -0
  15. data/lib/keight/skeleton/app/model.rb +144 -0
  16. data/lib/keight/skeleton/app/page/welcome.rb +17 -0
  17. data/lib/keight/skeleton/app/template/_layout.html.eruby +56 -0
  18. data/lib/keight/skeleton/app/template/welcome.html.eruby +6 -0
  19. data/lib/keight/skeleton/app/usecase/.keep +0 -0
  20. data/lib/keight/skeleton/config/app.rb +29 -0
  21. data/lib/keight/skeleton/config/app_dev.private +11 -0
  22. data/lib/keight/skeleton/config/app_dev.rb +8 -0
  23. data/lib/keight/skeleton/config/app_prod.rb +7 -0
  24. data/lib/keight/skeleton/config/app_stg.rb +5 -0
  25. data/lib/keight/skeleton/config/app_test.private +11 -0
  26. data/lib/keight/skeleton/config/app_test.rb +8 -0
  27. data/lib/keight/skeleton/config/server_puma.rb +22 -0
  28. data/lib/keight/skeleton/config/server_unicorn.rb +21 -0
  29. data/lib/keight/skeleton/config/urlpath_mapping.rb +16 -0
  30. data/lib/keight/skeleton/config.rb +44 -0
  31. data/lib/keight/skeleton/config.ru +21 -0
  32. data/lib/keight/skeleton/index.txt +38 -0
  33. data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js +6 -0
  34. data/lib/keight/skeleton/static/lib/jquery/1.11.3/jquery.min.js.gz +0 -0
  35. data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js +4 -0
  36. data/lib/keight/skeleton/static/lib/modernizr/2.8.3/modernizr.min.js.gz +0 -0
  37. data/lib/keight/skeleton/tmp/upload/.keep +0 -0
  38. data/lib/keight.rb +2017 -0
  39. data/test/data/example1.jpg +0 -0
  40. data/test/data/example1.png +0 -0
  41. data/test/data/multipart.form +0 -0
  42. data/test/data/wabisabi.js +77 -0
  43. data/test/data/wabisabi.js.gz +0 -0
  44. data/test/keight_test.rb +3161 -0
  45. data/test/oktest.rb +1537 -0
  46. 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