stud 0.0.8 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,26 +3,55 @@
3
3
  # * Compare performance of different implementations.
4
4
  # * run each implementation N times, compare runtimes (histogram, etc)
5
5
 
6
+ require "metriks"
7
+ require "stud/benchmark/rusage"
8
+
6
9
  module Stud
7
10
  module Benchmark
8
11
  def self.run(iterations=1, &block)
9
- i = 0
10
- data = []
11
- full_start = Time.now
12
- while i < iterations
13
- start = Time.now
14
- block.call
15
- duration = Time.now - start
16
- data << duration
17
- i += 1
18
- end
19
- return Results.new(data)
12
+ timer = Metriks::Timer.new
13
+ iterations.times { timer.time(&block) }
14
+ return Results.new(timer)
20
15
  end # def run
21
16
 
17
+ def self.runtimed(seconds=10, &block)
18
+ timer = Metriks::Timer.new
19
+ expiration = Time.now + seconds
20
+ timer.time(&block) while Time.now < expiration
21
+ return Results.new(timer)
22
+ end # def runtimed
23
+
24
+ def self.cputimed(seconds=10, &block)
25
+ timer = Metriks::Timer.new
26
+ expiration = Time.now + seconds
27
+ while Time.now < expiration
28
+ start = Stud::Benchmark::RUsage.get
29
+ block.call
30
+ finish = Stud::Benchmark::RUsage.get
31
+ cputime = (finish.user + finish.system) - (start.user + start.system)
32
+ timer.update(cputime)
33
+ end # while not expired
34
+ return Results.new(timer)
35
+ end # self.cpu
36
+
22
37
  class Results
23
38
  include Enumerable
24
39
  # Stolen from https://github.com/holman/spark/blob/master/spark
25
- TICKS = %w{▁ ▂ ▃ ▄ ▅ ▆ ▇ █}
40
+ # TICKS = %w{▁ ▂ ▃ ▄ ▅ ▆ ▇ █}
41
+
42
+ TICKS = ["\x1b[38;5;#{232 + 8}m_\x1b[0m"] + %w{▁ ▂ ▃ ▄ ▅ ▆ ▇ █}
43
+
44
+ #.collect do |tick|
45
+ # 256 color support, use grayscale
46
+ #1.times.collect do |shade|
47
+ # '38' is foreground
48
+ # '48' is background
49
+ # Grey colors start at 232, but let's use the brighter half.
50
+ # escape [ 38 ; 5 ; <color>
51
+ #"\x1b[38;5;#{232 + 12 + 2 * shade}m#{tick}\x1b[0m"
52
+ #end
53
+ #tick
54
+ #end.flatten
26
55
 
27
56
  def initialize(data)
28
57
  @data = data
@@ -39,86 +68,51 @@ module Stud
39
68
  end # def environment
40
69
 
41
70
  def each(&block)
42
- @data.each(&block)
71
+ @data.snapshot.each(&block)
43
72
  end # def each
44
73
 
45
- def log_distribution
46
- return distribution do |value|
47
- if value == 0
48
- 0 ... 0
49
- else
50
- tick = (Math.log2(value).floor).to_f rescue 0
51
- (2 ** tick) ... (2 ** (tick+1))
52
- end
53
- end
54
- end # def log_distribution
55
-
56
- def distribution(&range_compute)
57
- raise ArgumentError.new("Missing range computation block") if !block_given?
74
+ def min
75
+ return @data.min
76
+ end
58
77
 
59
- max = @data.max
60
- dist = Hash.new { |h,k| h[k] = 0 }
61
- each do |value|
62
- range = range_compute.call(value)
63
- dist[range] += 1
64
- end
65
- return dist
66
- end # def distribution
78
+ def max
79
+ return @data.max
80
+ end
67
81
 
68
82
  def mean
69
- if @mean.nil?
70
- total = Float(@data.count)
71
- @mean = sum / total
72
- end
73
- return @mean
83
+ return @data.mean
74
84
  end # def mean
75
85
 
76
86
  def stddev
77
- # sum of square deviations of mean divided by total values
78
- return Math.sqrt(inject(0) { |s, v| s + (v - mean) ** 2 } / (@data.count - 1))
87
+ # work around (Timer#stddev reports the variance)
88
+ # https://github.com/eric/metriks/pull/29
89
+ return @data.stddev ** 0.5
79
90
  end # def stddev
80
91
 
81
92
  def sum
82
- if @sum.nil?
83
- @sum = inject(0) { |s,v| s + v }
84
- end
85
- return @sum
93
+ return @data.instance_eval { @histogram.sum }
86
94
  end # def sum
87
95
 
88
- def to_s
89
- return "#{environment}: avg: #{mean} stddev: #{stddev}"
90
- end # def to_s
91
-
92
96
  def pretty_print
93
- min = @data.min
94
- max = @data.max
95
- zmax = Float(max - min) # "zero" at the 'min' value, offset the max.
96
- incr = 0.1 # 10% increments
97
- #dist = distribution do |value|
98
- #percent = (value - min) / zmax
99
- #if percent == 1
100
- #(1 - incr ... 1.0)
101
- #else
102
- #start = ((percent * 10).floor / 10.0)
103
- #start ... (start + incr)
104
- #end
105
- #end
106
- dist = log_distribution
97
+ puts self
98
+ end # def pretty_print
107
99
 
108
- total = dist.inject(0) { |sum, (step, count)| sum + count }
109
- sorted = dist.sort { |a,b| a.first.begin <=> b.first.begin }
110
- puts sorted.collect { |lower_bound, count|
111
- #puts lower_bound
112
- percent = (count / Float(total))
113
- "%40s: %s" % [lower_bound, (TICKS.last * (50 * percent).ceil)]
114
- }.join("\n")
100
+ def to_s(scale=min .. max, ticks=10)
101
+ snapshot = @data.snapshot
102
+ values = snapshot.instance_eval { @values }
103
+ scale_distance = scale.end - scale.begin
104
+ tick = scale_distance / ticks
105
+ dist = ticks.to_i.times.collect do |i|
106
+ range = (scale.begin + tick * i) ... (scale.begin + tick * (i+1))
107
+ hits = values.select { |v| range.include?(v) }.count
108
+ percent = hits / values.size.to_f
109
+ next TICKS[(TICKS.count * percent).ceil] || TICKS.last
110
+ end
115
111
 
116
- end # def pretty_print
112
+ return sprintf("%20s %s (%.4f ... %.4f, mean: %0.4f, stddev: %0.4f)",
113
+ environment, dist.join(""), scale.begin, scale.end,
114
+ mean, stddev)
115
+ end # def to_s
117
116
  end # class Stud::Benchmark::Result
118
117
  end # module Benchmark
119
118
  end # module Stud
120
-
121
- #require "thread"
122
- #mutex = Mutex.new
123
- #results = Stud::Benchmark.run(20) { mutex.synchronize { rand; rand; rand } }
124
- #results.pretty_print
@@ -0,0 +1,54 @@
1
+ require "ffi"
2
+
3
+ module Stud
4
+ module Benchmark
5
+ module LibC
6
+ extend FFI::Library
7
+ ffi_lib "libc.so.6"
8
+
9
+ attach_function :getrusage, [:int, :pointer], :int
10
+ end
11
+
12
+ class TimeVal < FFI::Struct
13
+ layout :tv_sec, :long,
14
+ :tv_usec, :int32
15
+
16
+ def to_f
17
+ return self[:tv_sec] + (self[:tv_usec] / 1_000_000.0)
18
+ end
19
+ end
20
+
21
+ class RUsage < FFI::Struct
22
+ layout :utime, TimeVal,
23
+ :stime, TimeVal,
24
+ :maxrss, :long,
25
+ :ixrss, :long,
26
+ :idrss, :long,
27
+ :isrss, :long,
28
+ :minflt, :long,
29
+ :majflt, :long,
30
+ :nswap, :long,
31
+ :inblock, :long,
32
+ :oublock, :long,
33
+ :msgsnd, :long,
34
+ :msgrcv, :long,
35
+ :nsignals, :long,
36
+ :nvcsw, :long,
37
+ :nivcsw, :long
38
+
39
+ def self.get
40
+ usage = RUsage.new
41
+ LibC.getrusage(0, usage)
42
+ return usage
43
+ end
44
+
45
+ def user
46
+ return self[:utime].to_f
47
+ end
48
+
49
+ def system
50
+ return self[:stime].to_f
51
+ end
52
+ end # class RUsage
53
+ end # module Benchmark
54
+ end # module Stud
data/lib/stud/interval.rb CHANGED
@@ -5,7 +5,7 @@ module Stud
5
5
  #
6
6
  # The execution patterns of this method should be that
7
7
  # the start time of 'block.call' should always be at time T*interval
8
- def interval(time, &block)
8
+ def self.interval(time, &block)
9
9
  start = Time.now
10
10
  while true
11
11
  block.call
@@ -20,4 +20,8 @@ module Stud
20
20
  end
21
21
  end # loop forever
22
22
  end # def interval
23
+
24
+ def interval(time, &block)
25
+ return Stud.interval(time, &block)
26
+ end # def interval
23
27
  end # module Stud
data/lib/stud/trap.rb CHANGED
@@ -19,7 +19,7 @@ module Stud
19
19
  end
20
20
 
21
21
  def self.simulate_signal(signal)
22
- puts "Simulate: #{signal}"
22
+ puts "Simulate: #{signal} w/ #{@traps[signal].count} callbacks"
23
23
  @traps[signal].each(&:call)
24
24
  end
25
25
  end
metadata CHANGED
@@ -1,89 +1,130 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
5
- prerelease:
4
+ version: 0.0.10
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - Jordan Sissel
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-06 00:00:00.000000000 Z
12
+ date: 2013-01-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- name: rspec
16
- requirement: !ruby/object:Gem::Requirement
15
+ name: metriks
16
+ version_requirements: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: !binary |-
21
+ MA==
17
22
  none: false
23
+ requirement: !ruby/object:Gem::Requirement
18
24
  requirements:
19
- - - ! '>='
25
+ - - ">="
20
26
  - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
27
+ version: !binary |-
28
+ MA==
29
+ none: false
23
30
  prerelease: false
31
+ type: :runtime
32
+ - !ruby/object:Gem::Dependency
33
+ name: ffi
24
34
  version_requirements: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: !binary |-
39
+ MA==
25
40
  none: false
41
+ requirement: !ruby/object:Gem::Requirement
26
42
  requirements:
27
- - - ! '>='
43
+ - - ">="
28
44
  - !ruby/object:Gem::Version
29
- version: '0'
45
+ version: !binary |-
46
+ MA==
47
+ none: false
48
+ prerelease: false
49
+ type: :runtime
30
50
  - !ruby/object:Gem::Dependency
31
- name: insist
32
- requirement: !ruby/object:Gem::Requirement
51
+ name: rspec
52
+ version_requirements: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: !binary |-
57
+ MA==
33
58
  none: false
59
+ requirement: !ruby/object:Gem::Requirement
34
60
  requirements:
35
- - - ! '>='
61
+ - - ">="
36
62
  - !ruby/object:Gem::Version
37
- version: '0'
38
- type: :development
63
+ version: !binary |-
64
+ MA==
65
+ none: false
39
66
  prerelease: false
67
+ type: :development
68
+ - !ruby/object:Gem::Dependency
69
+ name: insist
40
70
  version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: !binary |-
75
+ MA==
41
76
  none: false
77
+ requirement: !ruby/object:Gem::Requirement
42
78
  requirements:
43
- - - ! '>='
79
+ - - ">="
44
80
  - !ruby/object:Gem::Version
45
- version: '0'
46
- description: small reusable bits of code I'm tired of writing over and over. A library
47
- form of my software-patterns github repo.
81
+ version: !binary |-
82
+ MA==
83
+ none: false
84
+ prerelease: false
85
+ type: :development
86
+ description: small reusable bits of code I'm tired of writing over and over. A library form of my software-patterns github repo.
48
87
  email: jls@semicomplete.com
49
88
  executables: []
50
89
  extensions: []
51
90
  extra_rdoc_files: []
52
91
  files:
92
+ - lib/stud/task.rb
93
+ - lib/stud/benchmark.rb
94
+ - lib/stud/pool.rb
53
95
  - lib/stud/try.rb
54
96
  - lib/stud/interval.rb
55
- - lib/stud/benchmark.rb
56
- - lib/stud/task.rb
57
97
  - lib/stud/trap.rb
58
98
  - lib/stud/secret.rb
59
- - lib/stud/pool.rb
99
+ - lib/stud/benchmark/rusage.rb
60
100
  - LICENSE
61
101
  - CHANGELIST
62
102
  - README.md
63
103
  homepage: https://github.com/jordansissel/ruby-stud
64
104
  licenses: []
65
- post_install_message:
105
+ post_install_message:
66
106
  rdoc_options: []
67
107
  require_paths:
68
108
  - lib
69
109
  - lib
70
110
  required_ruby_version: !ruby/object:Gem::Requirement
71
- none: false
72
111
  requirements:
73
- - - ! '>='
112
+ - - ">="
74
113
  - !ruby/object:Gem::Version
75
- version: '0'
76
- required_rubygems_version: !ruby/object:Gem::Requirement
114
+ version: !binary |-
115
+ MA==
77
116
  none: false
117
+ required_rubygems_version: !ruby/object:Gem::Requirement
78
118
  requirements:
79
- - - ! '>='
119
+ - - ">="
80
120
  - !ruby/object:Gem::Version
81
- version: '0'
121
+ version: !binary |-
122
+ MA==
123
+ none: false
82
124
  requirements: []
83
- rubyforge_project:
125
+ rubyforge_project:
84
126
  rubygems_version: 1.8.24
85
- signing_key:
127
+ signing_key:
86
128
  specification_version: 3
87
129
  summary: stud - common code techniques
88
130
  test_files: []
89
- has_rdoc: