hitimes 1.3.0-x64-mingw32
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.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +57 -0
- data/HISTORY.md +124 -0
- data/LICENSE +16 -0
- data/Manifest.txt +44 -0
- data/README.md +200 -0
- data/Rakefile +28 -0
- data/examples/benchmarks.rb +113 -0
- data/examples/stats.rb +31 -0
- data/ext/hitimes/c/extconf.rb +24 -0
- data/ext/hitimes/c/hitimes.c +37 -0
- data/ext/hitimes/c/hitimes_instant_clock_gettime.c +28 -0
- data/ext/hitimes/c/hitimes_instant_osx.c +45 -0
- data/ext/hitimes/c/hitimes_instant_windows.c +27 -0
- data/ext/hitimes/c/hitimes_interval.c +370 -0
- data/ext/hitimes/c/hitimes_interval.h +73 -0
- data/ext/hitimes/c/hitimes_stats.c +269 -0
- data/ext/hitimes/c/hitimes_stats.h +30 -0
- data/ext/hitimes/java/src/hitimes/Hitimes.java +66 -0
- data/ext/hitimes/java/src/hitimes/HitimesInterval.java +176 -0
- data/ext/hitimes/java/src/hitimes/HitimesService.java +16 -0
- data/ext/hitimes/java/src/hitimes/HitimesStats.java +112 -0
- data/lib/hitimes.rb +66 -0
- data/lib/hitimes/2.0/hitimes.so +0 -0
- data/lib/hitimes/2.1/hitimes.so +0 -0
- data/lib/hitimes/2.2/hitimes.so +0 -0
- data/lib/hitimes/2.3/hitimes.so +0 -0
- data/lib/hitimes/2.4/hitimes.so +0 -0
- data/lib/hitimes/2.5/hitimes.so +0 -0
- data/lib/hitimes/metric.rb +118 -0
- data/lib/hitimes/mutexed_stats.rb +32 -0
- data/lib/hitimes/paths.rb +53 -0
- data/lib/hitimes/stats.rb +58 -0
- data/lib/hitimes/timed_metric.rb +176 -0
- data/lib/hitimes/timed_value_metric.rb +233 -0
- data/lib/hitimes/value_metric.rb +71 -0
- data/lib/hitimes/version.rb +8 -0
- data/spec/hitimes_spec.rb +24 -0
- data/spec/interval_spec.rb +136 -0
- data/spec/metric_spec.rb +28 -0
- data/spec/mutex_stats_spec.rb +36 -0
- data/spec/paths_spec.rb +11 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/stats_spec.rb +98 -0
- data/spec/timed_metric_spec.rb +155 -0
- data/spec/timed_value_metric_spec.rb +171 -0
- data/spec/value_metric_spec.rb +108 -0
- data/spec/version_spec.rb +7 -0
- data/tasks/default.rake +242 -0
- data/tasks/extension.rake +38 -0
- data/tasks/this.rb +208 -0
- metadata +216 -0
@@ -0,0 +1,176 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008, 2009 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'forwardable'
|
7
|
+
module Hitimes
|
8
|
+
#
|
9
|
+
# A TimedMetric holds the metrics on how long it takes to do something. For
|
10
|
+
# example, measuring how long a method takes to operate.
|
11
|
+
#
|
12
|
+
# tm = TimedMetric.new( 'my-method' )
|
13
|
+
#
|
14
|
+
# 200.times do
|
15
|
+
# my_method_result = tm.measure do
|
16
|
+
# my_method( ... )
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# puts "#{ tm.name } operated at a rate of #{ tm.rate } calls per second"
|
21
|
+
#
|
22
|
+
# Since TimedMetric is a child class of Metric make sure to look at the
|
23
|
+
# Metric API also.
|
24
|
+
#
|
25
|
+
# A TimedMetric measures the execution time of an option with the Interval
|
26
|
+
# class.
|
27
|
+
#
|
28
|
+
# A TimedMetric contains a Stats object, therefore TimedMetric has +count+, +max+,
|
29
|
+
# +mean+, +min+, +rate+, +stddev+, +sum+, +sumsq+ methods that delegate to that Stats
|
30
|
+
# object for convenience.
|
31
|
+
#
|
32
|
+
#
|
33
|
+
class TimedMetric < Metric
|
34
|
+
# holds all the statistics
|
35
|
+
attr_reader :stats
|
36
|
+
|
37
|
+
class << TimedMetric
|
38
|
+
#
|
39
|
+
# :call-seq:
|
40
|
+
# TimedMetric.now -> TimedMetric
|
41
|
+
#
|
42
|
+
# Return a TimedMetric that has been started
|
43
|
+
#
|
44
|
+
def now( name, additional_data = {} )
|
45
|
+
t = TimedMetric.new( name, additional_data )
|
46
|
+
t.start
|
47
|
+
return t
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# :call-seq:
|
53
|
+
# TimedMetric.new( 'name') -> TimedMetric
|
54
|
+
# TimedMetric.new( 'name', 'other' => 'data') -> TimedMetric
|
55
|
+
#
|
56
|
+
# Create a new TimedMetric giving it a name and additional data.
|
57
|
+
# +additional_data+ may be anything that follows the +to_hash+ protocol
|
58
|
+
#
|
59
|
+
def initialize( name, additional_data = {} )
|
60
|
+
super( name, additional_data )
|
61
|
+
@stats = Stats.new
|
62
|
+
@current_interval = Interval.new
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# :call-seq:
|
67
|
+
# timed_metric.running? -> true or false
|
68
|
+
#
|
69
|
+
# return whether or not the timer is currently running.
|
70
|
+
#
|
71
|
+
def running?
|
72
|
+
@current_interval.running?
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# :call-seq:
|
77
|
+
# timed_metric.start -> nil
|
78
|
+
#
|
79
|
+
# Start the current metric, if the current metric is already started, then
|
80
|
+
# this is a noop.
|
81
|
+
#
|
82
|
+
def start
|
83
|
+
if not @current_interval.running? then
|
84
|
+
@current_interval.start
|
85
|
+
@sampling_start_time ||= self.utc_microseconds()
|
86
|
+
@sampling_start_interval ||= Interval.now
|
87
|
+
end
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# :call-seq:
|
93
|
+
# timed_metric.stop -> Float or nil
|
94
|
+
#
|
95
|
+
# Stop the current metric. This updates the stats and removes the current
|
96
|
+
# interval. If the timer was stopped then the duration of the last Interval
|
97
|
+
# is returned. If the timer was already stopped then false is returned and
|
98
|
+
# no stats are updated.
|
99
|
+
#
|
100
|
+
def stop
|
101
|
+
if @current_interval.running? then
|
102
|
+
d = @current_interval.stop
|
103
|
+
@stats.update( d )
|
104
|
+
@current_interval = Interval.new
|
105
|
+
|
106
|
+
# update the length of time we have been sampling
|
107
|
+
@sampling_delta = @sampling_start_interval.duration_so_far
|
108
|
+
|
109
|
+
return d
|
110
|
+
end
|
111
|
+
return false
|
112
|
+
end
|
113
|
+
|
114
|
+
#
|
115
|
+
# :call-seq:
|
116
|
+
# timed_metric.measure { ... } -> Object
|
117
|
+
#
|
118
|
+
# Measure the execution of a block and add those stats to the running stats.
|
119
|
+
# The return value is the return value of the block
|
120
|
+
#
|
121
|
+
def measure( &block )
|
122
|
+
return_value = nil
|
123
|
+
begin
|
124
|
+
start
|
125
|
+
return_value = yield
|
126
|
+
ensure
|
127
|
+
stop
|
128
|
+
end
|
129
|
+
return return_value
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# :call-seq:
|
134
|
+
# timed_metric.split -> Float
|
135
|
+
#
|
136
|
+
# Split the current TimedMetric. Essentially, mark a split time. This means
|
137
|
+
# stop the current interval and create a new interval, but make sure
|
138
|
+
# that the new interval lines up exactly, timewise, behind the previous
|
139
|
+
# interval.
|
140
|
+
#
|
141
|
+
# If the timer is running, then split returns the duration of the previous
|
142
|
+
# interval, i.e. the split-time. If the timer is not running, nothing
|
143
|
+
# happens and false is returned.
|
144
|
+
#
|
145
|
+
def split
|
146
|
+
if @current_interval.running? then
|
147
|
+
next_interval = @current_interval.split
|
148
|
+
d = @current_interval.duration
|
149
|
+
@stats.update( d )
|
150
|
+
@current_interval = next_interval
|
151
|
+
return d
|
152
|
+
end
|
153
|
+
return false
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# :call-seq:
|
158
|
+
# metric.to_hash -> Hash
|
159
|
+
#
|
160
|
+
# Convert the metric to a hash
|
161
|
+
#
|
162
|
+
def to_hash
|
163
|
+
h = super
|
164
|
+
Stats::STATS.each do |s|
|
165
|
+
h[s] = self.send( s )
|
166
|
+
end
|
167
|
+
return h
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
# forward appropriate calls directly to the stats object
|
172
|
+
extend Forwardable
|
173
|
+
def_delegators :@stats, :count, :max, :mean, :min, :rate, :stddev, :sum, :sumsq
|
174
|
+
alias :duration :sum
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008, 2009 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
module Hitimes
|
7
|
+
#
|
8
|
+
# A TimedValueMetric holds the metrics on how long it takes to do a batch of something.
|
9
|
+
# something. For measuring how long a method takes to operate on N items.
|
10
|
+
#
|
11
|
+
# tm = TimedValueMetric.new( 'my-batch-method' )
|
12
|
+
#
|
13
|
+
# 42.times do
|
14
|
+
# tm.start
|
15
|
+
# number_of_items_processed = do_something
|
16
|
+
# tm.stop( number_of_items_processed )
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# puts "#{ tm.name } operated at a rate of #{ tm.rate } calls per second"
|
20
|
+
#
|
21
|
+
# TimedValueMetric combines the usefulness of a ValueMetric and a TimedMetric.
|
22
|
+
# The stats are available for both the time it took to do the operation and
|
23
|
+
# the sizes of the batches that were run.
|
24
|
+
#
|
25
|
+
# A TimedValueMetric keeps track of both the time it took to do an operation
|
26
|
+
# and the size of the batch that was operated on. These metrics are kept
|
27
|
+
# separately as +timed_stats+ and +value_stats+ accessors.
|
28
|
+
#
|
29
|
+
class TimedValueMetric < Metric
|
30
|
+
# holds all the Timed statistics
|
31
|
+
attr_reader :timed_stats
|
32
|
+
|
33
|
+
# holds all the Value statistics
|
34
|
+
attr_reader :value_stats
|
35
|
+
|
36
|
+
class << TimedValueMetric
|
37
|
+
#
|
38
|
+
# :call-seq:
|
39
|
+
# TimedValueMetric.now( 'name' ) -> TimedValueMetric
|
40
|
+
#
|
41
|
+
# Return a TimedValueMetric that has been started
|
42
|
+
#
|
43
|
+
def now( name, additional_data = {} )
|
44
|
+
t = TimedValueMetric.new( name, additional_data )
|
45
|
+
t.start
|
46
|
+
return t
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# :call-seq:
|
52
|
+
# TimedValueMetric.new( 'name') -> TimedValueMetric
|
53
|
+
# TimedValueMetric.new( 'name', 'other' => 'data') -> TimedValueMetric
|
54
|
+
#
|
55
|
+
# Create a new TimedValueMetric giving it a name and additional data.
|
56
|
+
# +additional_data+ may be anything that follows the +to_hash+ protocol
|
57
|
+
#
|
58
|
+
def initialize( name, additional_data = {} )
|
59
|
+
super( name, additional_data )
|
60
|
+
@timed_stats = Stats.new
|
61
|
+
@value_stats = Stats.new
|
62
|
+
@current_interval = Interval.new
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# :call-seq:
|
67
|
+
# timed_value_metric.running? -> true or false
|
68
|
+
#
|
69
|
+
# return whether or not the metric is currently timing something.
|
70
|
+
#
|
71
|
+
def running?
|
72
|
+
@current_interval.running?
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# :call-seq:
|
77
|
+
# timed_value_metric.start -> nil
|
78
|
+
#
|
79
|
+
# Start the current timer, if the current timer is already started, then
|
80
|
+
# this is a noop.
|
81
|
+
#
|
82
|
+
def start
|
83
|
+
if not @current_interval.running? then
|
84
|
+
@current_interval.start
|
85
|
+
@sampling_start_time ||= self.utc_microseconds()
|
86
|
+
@sampling_start_interval ||= Interval.now
|
87
|
+
end
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
# :call-seq:
|
93
|
+
# timed_value_metric.stop( count ) -> Float or nil
|
94
|
+
#
|
95
|
+
# Stop the current metric. The +count+ parameter must be a
|
96
|
+
# value to update to the _value_ portion of the TimedValueMetric. Generally
|
97
|
+
# this is probably the number of things that were operated upon since
|
98
|
+
# +start+ was invoked.
|
99
|
+
#
|
100
|
+
# This updates both the +value_stats+ and +timed_stats+ stats and removes
|
101
|
+
# the current interval. If the metric is stopped then the duration of the
|
102
|
+
# last Interval is returned. If the metric was already stopped before this
|
103
|
+
# call, then false is returned and no stats are updated.
|
104
|
+
#
|
105
|
+
#
|
106
|
+
def stop( value )
|
107
|
+
if @current_interval.running? then
|
108
|
+
d = @current_interval.stop
|
109
|
+
@timed_stats.update( d )
|
110
|
+
@current_interval = Interval.new
|
111
|
+
@value_stats.update( value )
|
112
|
+
|
113
|
+
# update the lenght of time we have been sampling
|
114
|
+
@sampling_delta = @sampling_start_interval.duration_so_far
|
115
|
+
|
116
|
+
return d
|
117
|
+
end
|
118
|
+
return false
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# :call-seq:
|
123
|
+
# timed_value_metric.measure( value ) { ... } -> Object
|
124
|
+
#
|
125
|
+
# Measure the execution of a block and add those stats to the running stats.
|
126
|
+
# The return value is the return value of the block. A value must be passed
|
127
|
+
# into +measure+ to update the +value_stats+ portion of the TimedValueMetric.
|
128
|
+
#
|
129
|
+
def measure( value, &block )
|
130
|
+
return_value = nil
|
131
|
+
begin
|
132
|
+
start
|
133
|
+
return_value = yield
|
134
|
+
ensure
|
135
|
+
stop( value )
|
136
|
+
end
|
137
|
+
return return_value
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# :call-seq:
|
142
|
+
# timed_value_metric.split( value ) -> Float
|
143
|
+
#
|
144
|
+
# Split the current metric. Essentially, mark a split time. This means
|
145
|
+
# stop the current interval, with the givein +value+ and create a new
|
146
|
+
# interval, but make sure that the new interval lines up exactly, timewise,
|
147
|
+
# behind the previous interval.
|
148
|
+
#
|
149
|
+
# If the metric is running, then split returns the duration of the previous
|
150
|
+
# interval, i.e. the split-time. If the metric is not running, nothing
|
151
|
+
# happens, no stats are updated, and false is returned.
|
152
|
+
#
|
153
|
+
#
|
154
|
+
def split( value )
|
155
|
+
if @current_interval.running? then
|
156
|
+
next_interval = @current_interval.split
|
157
|
+
d = @current_interval.duration
|
158
|
+
@timed_stats.update( d )
|
159
|
+
@value_stats.update( value )
|
160
|
+
@current_interval = next_interval
|
161
|
+
return d
|
162
|
+
end
|
163
|
+
return false
|
164
|
+
end
|
165
|
+
|
166
|
+
#
|
167
|
+
# :call-seq:
|
168
|
+
# timed_value_metric.duration -> Float
|
169
|
+
#
|
170
|
+
# The duration of measured time from the metric.
|
171
|
+
#
|
172
|
+
def duration
|
173
|
+
@timed_stats.sum
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# :call-seq:
|
178
|
+
# timed_value_metric.unit_count -> Float
|
179
|
+
#
|
180
|
+
# The sum of all values passed to +stop+ or +skip+ or +measure+
|
181
|
+
#
|
182
|
+
def unit_count
|
183
|
+
@value_stats.sum
|
184
|
+
end
|
185
|
+
|
186
|
+
#
|
187
|
+
# :call-seq:
|
188
|
+
# timed_value_metric.rate -> Float
|
189
|
+
#
|
190
|
+
# Rate in the context of the TimedValueMetric is different than the
|
191
|
+
# TimedMetric. In the TimedValueMetric, each measurement of time is
|
192
|
+
# associated with a quantity of things done during that unit of time. So
|
193
|
+
# the +rate+ for a TimedValueMetric is the (sum of all quantities sampled) /
|
194
|
+
# ( sum of all durations measured )
|
195
|
+
#
|
196
|
+
# For example, say you were measuring, using a TimedValueMetric batch jobs
|
197
|
+
# that had individual units of work.
|
198
|
+
#
|
199
|
+
# tvm = TimedValueMetric.new( 'some-batch' )
|
200
|
+
# tvm.start
|
201
|
+
# # process a batch of 12 units
|
202
|
+
# duration1 = tvm.stop( 12 )
|
203
|
+
#
|
204
|
+
# tvm.start
|
205
|
+
# # process a larger batch of 42 units
|
206
|
+
# duration2 = tvm.stop( 42 )
|
207
|
+
#
|
208
|
+
# At this point the rate of units per second is calculated as ( 12 + 42 ) / ( duration1 + duration2 )
|
209
|
+
#
|
210
|
+
# some_batch_rate = tvm.rate # returns ( 34 / ( duration1+duration2 ) )
|
211
|
+
#
|
212
|
+
def rate
|
213
|
+
@value_stats.sum / @timed_stats.sum
|
214
|
+
end
|
215
|
+
|
216
|
+
#
|
217
|
+
# :call-seq:
|
218
|
+
# metric.to_hash -> Hash
|
219
|
+
#
|
220
|
+
# Convert the metric to a hash
|
221
|
+
#
|
222
|
+
def to_hash
|
223
|
+
h = super
|
224
|
+
h['timed_stats'] = @timed_stats.to_hash
|
225
|
+
h['value_stats'] = @value_stats.to_hash( Stats::STATS - %w[ rate ] )
|
226
|
+
h['rate'] = self.rate
|
227
|
+
h['unit_count'] = self.unit_count
|
228
|
+
return h
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
end
|
233
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008, 2009 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'forwardable'
|
7
|
+
module Hitimes
|
8
|
+
#
|
9
|
+
# A ValueMetric holds the data from measuring a single value over a period of
|
10
|
+
# time. In most cases this may be a single measurement at a single point in
|
11
|
+
# time.
|
12
|
+
#
|
13
|
+
# A good example of a ValueMetric is measuring the number of items in a queue.
|
14
|
+
#
|
15
|
+
# A ValueMetric contains a Stats object, therefore ValueMetric has +count+, +max+,
|
16
|
+
# +mean+, +min+, +stddev+, +sum+, +sumsq+ methods that delegate to that Stats
|
17
|
+
# object for convenience.
|
18
|
+
#
|
19
|
+
class ValueMetric < Metric
|
20
|
+
|
21
|
+
# holds all the statistics
|
22
|
+
attr_reader :stats
|
23
|
+
|
24
|
+
#
|
25
|
+
# :call-seq:
|
26
|
+
# ValueMetric.new( 'my_metric' ) -> ValueMetric
|
27
|
+
# ValueMetric.new( 'my_metric', 'foo' => 'bar', 'this' => 42 ) -> ValueMetric
|
28
|
+
#
|
29
|
+
# Create a new ValueMetric giving it a name and additional data.
|
30
|
+
# +additional_data+ may be anything that follows the +to_hash+ protocol.
|
31
|
+
#
|
32
|
+
def initialize( name, additional_data = {} )
|
33
|
+
super( name, additional_data )
|
34
|
+
@stats = Stats.new
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# :call-seq:
|
39
|
+
# metric.measure( value ) -> Float
|
40
|
+
#
|
41
|
+
# Give the +value+ as the measurement to the metric. The value is returned
|
42
|
+
#
|
43
|
+
def measure( value )
|
44
|
+
@sampling_start_time ||= self.utc_microseconds()
|
45
|
+
@sampling_start_interval ||= Interval.now
|
46
|
+
|
47
|
+
@stats.update( value )
|
48
|
+
|
49
|
+
# update the length of time we have been sampling
|
50
|
+
@sampling_delta = @sampling_start_interval.duration_so_far
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# :call-seq:
|
55
|
+
# metric.to_hash -> Hash
|
56
|
+
#
|
57
|
+
# Convert the metric to a hash
|
58
|
+
#
|
59
|
+
def to_hash
|
60
|
+
h = super
|
61
|
+
(Stats::STATS - %w[ rate ]).each do |s|
|
62
|
+
h[s] = self.send( s )
|
63
|
+
end
|
64
|
+
return h
|
65
|
+
end
|
66
|
+
|
67
|
+
# forward appropriate calls directly to the stats object
|
68
|
+
extend Forwardable
|
69
|
+
def_delegators :@stats, :count, :max, :mean, :min, :stddev, :sum, :sumsq
|
70
|
+
end
|
71
|
+
end
|