benchrb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ # Autotest.add_hook :initialize do |at|
6
+ # at.extra_files << "../some/external/dependency.rb"
7
+ #
8
+ # at.libs << ":../some/external"
9
+ #
10
+ # at.add_exception 'vendor'
11
+ #
12
+ # at.add_mapping(/dependency.rb/) do |f, _|
13
+ # at.files_matching(/test_.*rb$/)
14
+ # end
15
+ #
16
+ # %w(TestA TestB).each do |klass|
17
+ # at.extra_class_map[klass] = "test/test_misc.rb"
18
+ # end
19
+ # end
20
+
21
+ # Autotest.add_hook :run_command do |at|
22
+ # system "rake build"
23
+ # end
File without changes
@@ -0,0 +1,6 @@
1
+ === 1.0.0 / 2012-09-10
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
@@ -0,0 +1,8 @@
1
+ .autotest
2
+ History.rdoc
3
+ Manifest.txt
4
+ README.rdoc
5
+ Rakefile
6
+ bin/benchrb
7
+ lib/benchrb.rb
8
+ test/test_benchrb.rb
@@ -0,0 +1,54 @@
1
+ = BenchRb
2
+
3
+ * http://yaks.me/benchrb
4
+
5
+ == Description
6
+
7
+ Simple command line benchmarking for Ruby
8
+
9
+ == Synopsis
10
+
11
+ $ benchrb -n 100 "sleep 0.01"
12
+ $ benchrb # Interactive mode
13
+
14
+ == Requirements
15
+
16
+ * Ruby 1.9 or greater
17
+
18
+ == Install
19
+
20
+ * gem install benchrb
21
+
22
+ == Developers
23
+
24
+ After checking out the source, run:
25
+
26
+ $ rake newb
27
+
28
+ This task will install any missing dependencies, run the tests/specs,
29
+ and generate the RDoc.
30
+
31
+ == License
32
+
33
+ (The MIT License)
34
+
35
+ Copyright (c) 2012 Jeremie Castagna
36
+
37
+ Permission is hereby granted, free of charge, to any person obtaining
38
+ a copy of this software and associated documentation files (the
39
+ 'Software'), to deal in the Software without restriction, including
40
+ without limitation the rights to use, copy, modify, merge, publish,
41
+ distribute, sublicense, and/or sell copies of the Software, and to
42
+ permit persons to whom the Software is furnished to do so, subject to
43
+ the following conditions:
44
+
45
+ The above copyright notice and this permission notice shall be
46
+ included in all copies or substantial portions of the Software.
47
+
48
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
49
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
50
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
51
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
52
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
53
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
54
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,22 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ # Hoe.plugin :compiler
7
+ # Hoe.plugin :gem_prelude_sucks
8
+ # Hoe.plugin :inline
9
+ # Hoe.plugin :isolate
10
+ # Hoe.plugin :racc
11
+ # Hoe.plugin :rcov
12
+ # Hoe.plugin :rubyforge
13
+
14
+ Hoe.spec 'benchrb' do
15
+ self.readme_file = "README.rdoc"
16
+ self.history_file = "History.rdoc"
17
+ self.extra_rdoc_files = FileList['*.rdoc']
18
+
19
+ developer('Jeremie Castagna', 'yaksnrainbows@gmail.com')
20
+ end
21
+
22
+ # vim: syntax=ruby
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.join(File.dirname(__FILE__), "../lib") if $0 == "bin/benchrb"
4
+
5
+ require 'benchrb'
6
+ BenchRb.run_cmd
@@ -0,0 +1,495 @@
1
+ raise LoadError, "Ruby version must be >= 1.9" if RUBY_VERSION < "1.9"
2
+
3
+ require 'benchmark'
4
+
5
+ $benchrb_binding = binding
6
+
7
+ ##
8
+ # BenchRb is a simple wrapper around Ruby's Benchmark module which allows
9
+ # easily running a benchmark N times and getting averages, min, max, etc.
10
+
11
+ class BenchRb
12
+
13
+ # Gem version
14
+ VERSION = '1.0.0'
15
+
16
+
17
+ ##
18
+ # Parse command line arguments.
19
+
20
+ def self.parse_args argv
21
+ require 'optparse'
22
+
23
+ options = {}
24
+
25
+ opts = OptionParser.new do |opt|
26
+ opt.program_name = File.basename $0
27
+ opt.version = BenchRb::VERSION
28
+ opt.release = nil
29
+
30
+ opt.banner = <<-STR
31
+
32
+ #{opt.program_name} #{opt.version}
33
+
34
+ Quickly benchmark ruby code.
35
+
36
+ Usage:
37
+ #{opt.program_name} --help
38
+ #{opt.program_name} --version
39
+ #{opt.program_name} [options] [ruby code]
40
+
41
+ Examples:
42
+ #{opt.program_name} "[0, 1, 2, 3].inject(1){|last, num| last + num}"
43
+ #{opt.program_name} -n 1000000 "2**10"
44
+
45
+
46
+ Running without ruby code argument will open an interactive shell.
47
+
48
+ Options:
49
+ STR
50
+
51
+ opt.on('-n', '--number INT', Integer,
52
+ 'Number of times to run the code (default 10000)') do |count|
53
+ options[:count] = count
54
+ end
55
+
56
+ opt.on('-r MODULE', String, 'Same as `ruby -r\'') do |lib|
57
+ require lib
58
+ end
59
+
60
+ opt.on('-I PATH', String, 'Specify $LOAD_PATH directory') do |path|
61
+ $:.unshift path
62
+ end
63
+
64
+ opt.on('-h', '--help', 'Print this help screen') do
65
+ puts opt
66
+ exit
67
+ end
68
+
69
+ opt.on('-v', '--version', 'Output version and exit') do
70
+ puts BenchRb::VERSION
71
+ exit
72
+ end
73
+ end
74
+
75
+ opts.parse! argv
76
+
77
+ return [argv.last, options]
78
+ end
79
+
80
+
81
+ ##
82
+ # Run from the command line.
83
+
84
+ def self.run_cmd argv=ARGV
85
+ res = run(*parse_args(argv))
86
+ puts res.inspect if res
87
+ end
88
+
89
+
90
+ ##
91
+ # Run and benchmark a Ruby String or block. Returns a BenchRb instance.
92
+ # If no Ruby String or block is given, runs in a loop while expecting
93
+ # input from $stdin.
94
+ #
95
+ # Supported options:
96
+ # :binding:: The binding to run the String as (not for blocks)
97
+ # :count:: The number of times to run the given code
98
+ #
99
+ # Examples:
100
+ # BenchRb.run "sleep 0.01", :count => 10
101
+ #
102
+ # BenchRb.run :count => 10 do
103
+ # sleep 0.01
104
+ # end
105
+
106
+ def self.run rb_str=nil, opts={}, &block
107
+ rb_str, opts = nil, rb_str if Hash === rb_str
108
+
109
+ if rb_str
110
+ bind = opts[:binding] || $benchrb_binding
111
+ block = eval("lambda do\n#{rb_str}\nend", bind)
112
+ end
113
+
114
+ if block
115
+ self.bench(opts[:count], &block)
116
+
117
+ else
118
+ self.console opts
119
+ end
120
+ end
121
+
122
+
123
+ ##
124
+ # Benchmark a block of code with a given count. Count defaults to 1.
125
+ # Returns a BenchRb instance.
126
+
127
+ def self.bench count=nil, &block
128
+ count = 1 if !count || count < 1
129
+ result = new
130
+
131
+ GC.start
132
+
133
+ count.times do
134
+ bm = Benchmark.measure(&block)
135
+ result.add [bm.utime, bm.stime, bm.total, bm.real]
136
+ end
137
+
138
+ return result
139
+ end
140
+
141
+
142
+ ##
143
+ # Interactive console mode. Takes the same options as BenchRb.run.
144
+
145
+ def self.console opts={}
146
+ help = [
147
+ "`exit' to quit",
148
+ "`help' for help screen",
149
+ "`pause' to stop benchmarking temporarily",
150
+ "`bench' to start benchmarking again",
151
+ "`-n NUM' to change the benchmark count",
152
+ "End lines with `\\' to run multiple lines"
153
+ ]
154
+
155
+ trap(:INT){ puts "\n"; exit 1 }
156
+
157
+ $stderr.puts help.join("\n")
158
+ $stderr.puts "\n"
159
+
160
+ console = Console.new :prompt => "bench> "
161
+ paused = false
162
+
163
+ ruby = ""
164
+
165
+ loop do
166
+ str = console.read_line.strip
167
+
168
+ case str
169
+ when ""
170
+ next
171
+
172
+ when "exit"
173
+ break
174
+
175
+ when "help"
176
+ $stderr.puts help.join("\n")
177
+ $stderr.puts "\n"
178
+ next
179
+
180
+ when "pause"
181
+ paused = true
182
+ console.prompt = "ruby> "
183
+ next
184
+
185
+ when "bench"
186
+ paused = false
187
+ console.prompt = "bench> "
188
+ next
189
+
190
+ when /^-n *(\d+)$/
191
+ opts[:count] = $1.to_i
192
+ puts "Count set to #{$1}"
193
+ next
194
+
195
+ else
196
+ ruby << str
197
+ end
198
+
199
+ ruby[-1] = "\n" and next if ruby[-1] == "\\"
200
+
201
+ res = begin
202
+ if paused
203
+ "=> #{eval(ruby, opts[:binding] || $benchrb_binding).inspect}"
204
+ else
205
+ run(ruby, opts).inspect
206
+ end
207
+
208
+ rescue SystemExit, SignalException
209
+ raise
210
+
211
+ rescue Exception => err
212
+ "#{err.class}: #{err.message}\n#{err.backtrace.map{|b| "\tfrom #{b}"}.
213
+ join("\n")}"
214
+ end
215
+
216
+ ruby = ""
217
+ puts res
218
+ end
219
+ end
220
+
221
+
222
+ attr_accessor :value
223
+
224
+ ##
225
+ # Create a new BenchRb instance for recording results.
226
+
227
+ def initialize
228
+ @map = %w{user system total real}
229
+ @min = [0,0,0,0]
230
+ @max = [0,0,0,0]
231
+ @avg = [0,0,0,0]
232
+ @tot = [0,0,0,0]
233
+ @count = 0
234
+ @value = nil
235
+ end
236
+
237
+
238
+ ##
239
+ # Append a result. Result should be an Array of the following form:
240
+ # [user_time, system_time, total_time, real_time]
241
+
242
+ def add results
243
+ if @count == 0
244
+ @min = results.dup
245
+ @max = results.dup
246
+ @avg = results.dup
247
+ @count += 1
248
+ return self
249
+ end
250
+
251
+ results.each_with_index do |num, index|
252
+ @avg[index] = ((@avg[index] * @count) + num) / (@count + 1.0)
253
+ @min[index] = num if @min[index] > num
254
+ @max[index] = num if @max[index] < num
255
+ @tot[index] += num
256
+ end
257
+
258
+ @count += 1
259
+ return self
260
+ end
261
+
262
+
263
+ ##
264
+ # Inspect the instance. Renders the output grid as a String.
265
+
266
+ def inspect
267
+ grid = [
268
+ [" ", @map.dup],
269
+ ["avg", @avg.map{|num| num_to_str(num)} ],
270
+ ["min", @min.map{|num| num_to_str(num)} ],
271
+ ["max", @max.map{|num| num_to_str(num)} ],
272
+ ["tot", @tot.map{|num| num_to_str(num)} ]
273
+ ]
274
+
275
+ longest = 9
276
+ grid.flatten.each{|item| longest = item.length if longest < item.length }
277
+
278
+ out = ""
279
+
280
+ grid.each do |(name, ary)|
281
+ out << "#{name} #{ary.map{|item| item.ljust(longest, " ")}.join(" ")}\n"
282
+ end
283
+
284
+ out
285
+ end
286
+
287
+
288
+ ##
289
+ # Turn a number into a padded String with a target length.
290
+
291
+ def num_to_str num, len=9
292
+ str = num.to_f.round(len-2).to_s
293
+ sci = !str.index("e").nil?
294
+
295
+ rnd = len - str.index(".") - 1
296
+ str = num.to_f.round(rnd).to_s.ljust(len, "0") if rnd > 0 && !sci
297
+
298
+ return str if str.length == len
299
+
300
+ str = str.split(".", 2)[0] if !sci
301
+ str.rjust(len, " ")
302
+ end
303
+
304
+
305
+ class Console
306
+
307
+ attr_accessor :prompt, :history, :max_history
308
+
309
+ def initialize opts={}
310
+ @max_history = opts[:max_history] || 1000
311
+ @history = Array(opts[:history])
312
+ @prompt = opts[:prompt] || ">> "
313
+ end
314
+
315
+
316
+ def read_line
317
+ old_state = `stty -g`
318
+ system "stty raw -echo"
319
+
320
+ hindex = @history.length
321
+ cpos = write_line ""
322
+
323
+ line = ""
324
+ disp = line
325
+
326
+ loop do
327
+ ch = read_char
328
+
329
+ case ch
330
+ when "\e"
331
+ # Got escape by itself. Do nothing.
332
+
333
+ when "\u0001" # ctrl+A - BOL
334
+ cpos = set_wpos(0)
335
+
336
+ when "\u0005" # ctrl+E - EOL
337
+ cpos = set_wpos(disp.length)
338
+
339
+ when "\u0017" # ctrl+W - erase word
340
+ i = disp.rstrip.rindex(" ")
341
+ disp = i ? disp[0..i] : ""
342
+ cpos = write_line disp
343
+
344
+ when "\u0015" # ctrl+U - erase all
345
+ disp.clear
346
+ cpos = write_line disp
347
+
348
+ when "\u0003" # ctrl+C - SIGINT
349
+ set_cpos(0)
350
+ Process.kill "INT", Process.pid
351
+ break
352
+
353
+ when "\e[A", "\u0010" # Up Arrow, Ctrl+P
354
+ hindex = hindex - 1
355
+ hindex = 0 if hindex < 0
356
+ if @history[hindex]
357
+ disp = @history[hindex].dup
358
+ cpos = write_line disp
359
+ end
360
+
361
+ when "\e[B", "\u000E" # Down Arrow, Ctrl+N
362
+ hindex = hindex + 1
363
+ hindex = @history.length if hindex > @history.length
364
+ disp = hindex == @history.length ? line : @history[hindex].dup
365
+ cpos = write_line disp
366
+
367
+ when "\e[C", "\u0006" # Right Arrow, Ctrl+F
368
+ if cpos < (@prompt.length + disp.length + 1)
369
+ cpos = cpos + 1
370
+ $stdout.print "\e[#{cpos}G"
371
+ end
372
+
373
+ when "\e[D", "\u0002" # Left Arrow, Ctrl+B
374
+ if cpos > @prompt.length + 1
375
+ cpos = set_cpos(cpos - 1)
376
+ end
377
+
378
+ when "\r", "\n" # Enter - commit line
379
+ line = disp
380
+ $stdout.puts ch
381
+ break
382
+
383
+ when "\u007F", "\b" # Delete
384
+ if cpos > @prompt.length + 1
385
+ cpos = cpos - 1
386
+ wpos = cpos - @prompt.length - 1
387
+ disp[wpos,1] = ""
388
+ write_line disp
389
+ set_cpos cpos
390
+ end
391
+
392
+ when "\t" # Tab
393
+
394
+ else
395
+ wpos = cpos - @prompt.length - 1
396
+ disp[wpos,0] = ch
397
+ write_line disp
398
+ cpos = set_cpos(cpos + 1)
399
+ end
400
+
401
+ $stdout.flush
402
+ end
403
+
404
+ @history << line unless line.strip.empty? || @history[-1] == line
405
+ @history = @history[@history.length-@max_history..-1] if
406
+ @history.length > @max_history
407
+
408
+ line
409
+
410
+ ensure
411
+ system "stty #{old_state}"
412
+ end
413
+
414
+
415
+ def write_line line
416
+ text = "#{@prompt}#{line}"
417
+ $stdout.print "\e[2K\e[0G#{text}"
418
+ $stdout.flush
419
+ text.length + 1
420
+ end
421
+
422
+
423
+ def set_wpos num
424
+ pos = @prompt.length + num + 1
425
+ $stdout.print "\e[#{pos}G"
426
+ pos
427
+ end
428
+
429
+
430
+ def set_cpos num
431
+ $stdout.print "\e[#{num}G"
432
+ num
433
+ end
434
+
435
+
436
+ def read_char
437
+ c = ""
438
+
439
+ begin
440
+ # save previous state of stty
441
+ #old_state = `stty -g`
442
+ # disable echoing and enable raw (not having to press enter)
443
+ #system "stty raw -echo"
444
+ c = $stdin.getc.chr
445
+ # gather next two characters of special keys
446
+ if(c=="\e")
447
+ extra_thread = Thread.new{
448
+ c = c + $stdin.getc.chr
449
+ c = c + $stdin.getc.chr
450
+ }
451
+ # wait just long enough for special keys to get swallowed
452
+ extra_thread.join(0.0001)
453
+ # kill thread so not-so-long special keys don't wait on getc
454
+ extra_thread.kill
455
+ end
456
+
457
+ rescue => ex
458
+ puts "#{ex.class}: #{ex.message}"
459
+ #ensure
460
+ # restore previous state of stty
461
+ #system "stty #{old_state}"
462
+ end
463
+
464
+ return c
465
+ end
466
+ end
467
+ end
468
+
469
+
470
+ class Object
471
+ ##
472
+ # Convenience method for printing benchmarks inline with code.
473
+ # bench 100, "sleep 0.01"
474
+ # bench{ sleep 0.01 }
475
+ #
476
+ # Interactive mode with the current binding:
477
+ # bench binding
478
+
479
+ def bench *args, &block
480
+ count = 1
481
+ binding = nil
482
+ rb_str = nil
483
+
484
+ args.each do |val|
485
+ case val
486
+ when String then rb_str = val
487
+ when Integer then count = val
488
+ when Binding then binding = val
489
+ end
490
+ end
491
+
492
+ puts BenchRb.run(rb_str, :count => count, :binding => binding, &block).inspect
493
+ puts "Caller: #{caller[0]}"
494
+ end
495
+ end
@@ -0,0 +1,7 @@
1
+ require "test/unit"
2
+ require "benchrb"
3
+
4
+ class TestBenchRb < Test::Unit::TestCase
5
+ def test_sanity
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: benchrb
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jeremie Castagna
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-09-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rdoc
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '3.10'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '3.10'
30
+ - !ruby/object:Gem::Dependency
31
+ name: hoe
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '3.0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '3.0'
46
+ description: Simple command line benchmarking for Ruby
47
+ email:
48
+ - yaksnrainbows@gmail.com
49
+ executables:
50
+ - benchrb
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - History.rdoc
54
+ - Manifest.txt
55
+ - README.rdoc
56
+ files:
57
+ - .autotest
58
+ - History.rdoc
59
+ - Manifest.txt
60
+ - README.rdoc
61
+ - Rakefile
62
+ - bin/benchrb
63
+ - lib/benchrb.rb
64
+ - test/test_benchrb.rb
65
+ - .gemtest
66
+ homepage: http://yaks.me/benchrb
67
+ licenses: []
68
+ post_install_message:
69
+ rdoc_options:
70
+ - --main
71
+ - README.rdoc
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ requirements: []
87
+ rubyforge_project: benchrb
88
+ rubygems_version: 1.8.24
89
+ signing_key:
90
+ specification_version: 3
91
+ summary: Simple command line benchmarking for Ruby
92
+ test_files:
93
+ - test/test_benchrb.rb