benchrb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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