stud 0.0.8 → 0.0.10
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.
- data/lib/stud/benchmark.rb +70 -76
- data/lib/stud/benchmark/rusage.rb +54 -0
- data/lib/stud/interval.rb +5 -1
- data/lib/stud/trap.rb +1 -1
- metadata +74 -33
data/lib/stud/benchmark.rb
CHANGED
@@ -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
|
-
|
10
|
-
|
11
|
-
|
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
|
46
|
-
return
|
47
|
-
|
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
|
-
|
60
|
-
|
61
|
-
|
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
|
-
|
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
|
-
#
|
78
|
-
|
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
|
-
|
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
|
-
|
94
|
-
|
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
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
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
|
-
|
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
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.
|
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:
|
12
|
+
date: 2013-01-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
|
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:
|
22
|
-
|
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:
|
45
|
+
version: !binary |-
|
46
|
+
MA==
|
47
|
+
none: false
|
48
|
+
prerelease: false
|
49
|
+
type: :runtime
|
30
50
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
32
|
-
|
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:
|
38
|
-
|
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:
|
46
|
-
|
47
|
-
|
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/
|
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:
|
76
|
-
|
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:
|
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:
|