hitimes 0.4.1-x86-mswin32-60 → 1.0.0-x86-mswin32-60

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,240 @@
1
+ #--
2
+ # Copyright (c) 2008, 2009 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ require 'hitimes'
7
+
8
+ module Hitimes
9
+ #
10
+ # A TimedValueMetric holds the metrics on how long it takes to do a batch of something.
11
+ # something. For measuring how long a method takes to operate on N items.
12
+ #
13
+ # tm = TimedValueMetric.new( 'my-batch-method' )
14
+ #
15
+ # 42.times do
16
+ # tm.start
17
+ # number_of_items_processed = do_something
18
+ # tm.stop( number_of_items_processed )
19
+ # end
20
+ #
21
+ # puts "#{ tm.name } operated at a rate of #{ tm.rate } calls per second"
22
+ #
23
+ # TimedValueMetric combines the usefulness of a ValueMetric and a TimedMetric.
24
+ # The stats are available for both the time it took to do the operation and
25
+ # the sizes of the batches that were run.
26
+ #
27
+ # A TimedValueMetric keeps track of both the time it took to do an operation
28
+ # and the size of the batch that was operated on. These metrics are kept
29
+ # separately as +timed_stats+ and +value_stats+ accessors.
30
+ #
31
+ class TimedValueMetric < Metric
32
+ # holds all the Timed statistics
33
+ attr_reader :timed_stats
34
+
35
+ # holds all the Value statistics
36
+ attr_reader :value_stats
37
+
38
+ class << TimedValueMetric
39
+ #
40
+ # :call-seq:
41
+ # TimedValueMetric.now( 'name' ) -> TimedValueMetric
42
+ #
43
+ # Return a TimedValueMetric that has been started
44
+ #
45
+ def now( name, additional_data = {} )
46
+ t = TimedValueMetric.new( name, additional_data )
47
+ t.start
48
+ return t
49
+ end
50
+ end
51
+
52
+ #
53
+ # :call-seq:
54
+ # TimedValueMetric.new( 'name') -> TimedValueMetric
55
+ # TimedValueMetric.new( 'name', 'other' => 'data') -> TimedValueMetric
56
+ #
57
+ # Create a new TimedValueMetric giving it a name and additional data.
58
+ # +additional_data+ may be anything that follows the +to_hash+ protocol
59
+ #
60
+ def initialize( name, additional_data = {} )
61
+ super( name, additional_data )
62
+ @current_interval = nil
63
+ @timed_stats = Stats.new
64
+ @value_stats = Stats.new
65
+ end
66
+
67
+ #
68
+ # :call-seq:
69
+ # timed_value_metric.current_interval -> Interval
70
+ #
71
+ # Return the current interval, if one doesn't exist create one.
72
+ #
73
+ def current_interval
74
+ @current_interval ||= Interval.new
75
+ end
76
+
77
+
78
+ #
79
+ # :call-seq:
80
+ # timed_value_metric.running? -> true or false
81
+ #
82
+ # return whether or not the metric is currently timing something.
83
+ #
84
+ def running?
85
+ current_interval.running?
86
+ end
87
+
88
+ #
89
+ # :call-seq:
90
+ # timed_value_metric.start -> nil
91
+ #
92
+ # Start the current timer, if the current timer is already started, then
93
+ # this is a noop.
94
+ #
95
+ def start
96
+ current_interval.start unless running?
97
+ @sampling_start_time ||= self.utc_microseconds()
98
+ nil
99
+ end
100
+
101
+ #
102
+ # :call-seq:
103
+ # timed_value_metric.stop( count ) -> Float or nil
104
+ #
105
+ # Stop the current metric. The +count+ parameter must be a
106
+ # value to update to the _value_ portion of the TimedValueMetric. Generally
107
+ # this is probably the number of things that were operated upon since
108
+ # +start+ was invoked.
109
+ #
110
+ # This updates both the +value_stats+ and +timed_stats+ stats and removes
111
+ # the current interval. If the metric is stopped then the duration of the
112
+ # last Interval is returned. If the metric was already stopped before this
113
+ # call, then false is returned and no stats are updated.
114
+ #
115
+ #
116
+ def stop( value )
117
+ if running? then
118
+ d = current_interval.stop
119
+ @current_interval = nil
120
+ @sampling_stop_time = self.utc_microseconds()
121
+ @timed_stats.update( d )
122
+ @value_stats.update( value )
123
+ return d
124
+ end
125
+ return false
126
+ end
127
+
128
+ #
129
+ # :call-seq:
130
+ # timed_value_metric.measure( value ) { ... } -> Object
131
+ #
132
+ # Measure the execution of a block and add those stats to the running stats.
133
+ # The return value is the return value of the block. A value must be passed
134
+ # into +measure+ to update the +value_stats+ portion of the TimedValueMetric.
135
+ #
136
+ def measure( value, &block )
137
+ return_value = nil
138
+ begin
139
+ start
140
+ return_value = yield
141
+ ensure
142
+ stop( value )
143
+ end
144
+ return return_value
145
+ end
146
+
147
+ #
148
+ # :call-seq:
149
+ # timed_value_metric.split( value ) -> Float
150
+ #
151
+ # Split the current metric. Essentially, mark a split time. This means
152
+ # stop the current interval, with the givein +value+ and create a new
153
+ # interval, but make sure that the new interval lines up exactly, timewise,
154
+ # behind the previous interval.
155
+ #
156
+ # If the metric is running, then split returns the duration of the previous
157
+ # interval, i.e. the split-time. If the metric is not running, nothing
158
+ # happens, no stats are updated, and false is returned.
159
+ #
160
+ #
161
+ def split( value )
162
+ if running? then
163
+ next_interval = current_interval.split
164
+ d = current_interval.duration
165
+ @timed_stats.update( d )
166
+ @value_stats.update( value )
167
+ @current_interval = next_interval
168
+ return d
169
+ end
170
+ return false
171
+ end
172
+
173
+ #
174
+ # :call-seq:
175
+ # timed_value_metric.duration -> Float
176
+ #
177
+ # The duration of measured time from the metric.
178
+ #
179
+ def duration
180
+ @timed_stats.sum
181
+ end
182
+
183
+ #
184
+ # :call-seq:
185
+ # timed_value_metric.unit_count -> Float
186
+ #
187
+ # The sum of all values passed to +stop+ or +skip+ or +measure+
188
+ #
189
+ def unit_count
190
+ @value_stats.sum
191
+ end
192
+
193
+ #
194
+ # :call-seq:
195
+ # timed_value_metric.rate -> Float
196
+ #
197
+ # Rate in the context of the TimedValueMetric is different than the
198
+ # TimedMetric. In the TimedValueMetric, each measurement of time is
199
+ # associated with a quantity of things done during that unit of time. So
200
+ # the +rate+ for a TimedValueMetric is the (sum of all quantities sampled) /
201
+ # ( sum of all durations measured )
202
+ #
203
+ # For example, say you were measuring, using a TimedValueMetric batch jobs
204
+ # that had individual units of work.
205
+ #
206
+ # tvm = TimedValueMetric.new( 'some-batch' )
207
+ # tvm.start
208
+ # # process a batch of 12 units
209
+ # duration1 = tvm.stop( 12 )
210
+ #
211
+ # tvm.start
212
+ # # process a larger batch of 42 units
213
+ # duration2 = tvm.stop( 42 )
214
+ #
215
+ # At this point the rate of units per second is calculated as ( 12 + 42 ) / ( duration1 + duration2 )
216
+ #
217
+ # some_batch_rate = tvm.rate # returns ( 34 / ( duration1+duration2 ) )
218
+ #
219
+ def rate
220
+ @value_stats.sum / @timed_stats.sum
221
+ end
222
+
223
+ #
224
+ # :call-seq:
225
+ # metric.to_hash -> Hash
226
+ #
227
+ # Convert the metric to a hash
228
+ #
229
+ def to_hash
230
+ h = super
231
+ h['timed_stats'] = @timed_stats.to_hash
232
+ h['value_stats'] = @value_stats.to_hash( Stats::STATS - %w[ rate ] )
233
+ h['rate'] = self.rate
234
+ h['unit_count'] = self.unit_count
235
+ return h
236
+ end
237
+
238
+
239
+ end
240
+ end
@@ -0,0 +1,69 @@
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
+ require 'hitimes'
8
+ module Hitimes
9
+ #
10
+ # A ValueMetric holds the data from measuring a single value over a period of
11
+ # time. In most cases this may be a single measurement at a single point in
12
+ # time.
13
+ #
14
+ # A good example of a ValueMetric is measuring the number of items in a queue.
15
+ #
16
+ # A ValueMetric contains a Stats object, therefore ValueMetric has +count+, +max+,
17
+ # +mean+, +min+, +stddev+, +sum+, +sumsq+ methods that delegate to that Stats
18
+ # object for convenience.
19
+ #
20
+ class ValueMetric < Metric
21
+
22
+ # holds all the statistics
23
+ attr_reader :stats
24
+
25
+ #
26
+ # :call-seq:
27
+ # ValueMetric.new( 'my_metric' ) -> ValueMetric
28
+ # ValueMetric.new( 'my_metric', 'foo' => 'bar', 'this' => 42 ) -> ValueMetric
29
+ #
30
+ # Create a new ValueMetric giving it a name and additional data.
31
+ # +additional_data+ may be anything that follows the +to_hash+ protocol.
32
+ #
33
+ def initialize( name, additional_data = {} )
34
+ super( name, additional_data )
35
+ @stats = Stats.new
36
+ end
37
+
38
+ #
39
+ # :call-seq:
40
+ # metric.measure( value ) -> Float
41
+ #
42
+ # Give the +value+ as the measurement to the metric. The value is returned
43
+ #
44
+ def measure( value )
45
+ now = self.utc_microseconds()
46
+ @sampling_start_time ||= now
47
+ @sampling_stop_time = now
48
+ @stats.update( value )
49
+ end
50
+
51
+ #
52
+ # :call-seq:
53
+ # metric.to_hash -> Hash
54
+ #
55
+ # Convert the metric to a hash
56
+ #
57
+ def to_hash
58
+ h = super
59
+ (Stats::STATS - %w[ rate ]).each do |s|
60
+ h[s] = self.send( s )
61
+ end
62
+ return h
63
+ end
64
+
65
+ # forward appropriate calls directly to the stats object
66
+ extend Forwardable
67
+ def_delegators :@stats, :count, :sum, :max, :mean, :min, :stddev, :sum, :sumsq
68
+ end
69
+ end
@@ -9,9 +9,14 @@ module Hitimes
9
9
  #
10
10
  module Version
11
11
 
12
- MAJOR = 0
13
- MINOR = 4
14
- BUILD = 1
12
+ # Major version number
13
+ MAJOR = 1
14
+
15
+ # Minor version number
16
+ MINOR = 0
17
+
18
+ # Build number
19
+ BUILD = 0
15
20
 
16
21
  #
17
22
  # :call-seq:
@@ -19,24 +24,34 @@ module Hitimes
19
24
  #
20
25
  # Return the version as an array of Integers
21
26
  #
22
- def to_a
27
+ def self.to_a
23
28
  [MAJOR, MINOR, BUILD]
24
29
  end
25
30
 
26
31
  #
27
32
  # :call-seq:
28
- # Version.to_s -> MAJOR.MINOR.BUILD
33
+ # Version.to_s -> "MAJOR.MINOR.BUILD"
29
34
  #
30
35
  # Return the version as a String with dotted notation
31
36
  #
32
- def to_s
37
+ def self.to_s
33
38
  to_a.join(".")
34
39
  end
35
40
 
36
- module_function :to_a
37
- module_function :to_s
41
+ #
42
+ # :call-seq:
43
+ # Version.to_hash -> { :major => ..., :minor => ..., :build => ... }
44
+ #
45
+ # Return the version as a Hash
46
+ #
47
+ def self.to_hash
48
+ { :major => MAJOR, :minor => MINOR, :build => BUILD }
49
+ end
38
50
 
51
+ # The Version in MAJOR.MINOR.BUILD dotted notation
39
52
  STRING = Version.to_s
40
53
  end
54
+
55
+ # The Version in MAJOR.MINOR.BUILD dotted notation
41
56
  VERSION = Version.to_s
42
57
  end
data/lib/hitimes_ext.so CHANGED
Binary file
@@ -0,0 +1,30 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), "spec_helper.rb" ) )
2
+
3
+ require 'hitimes/metric'
4
+
5
+ describe Hitimes::Metric do
6
+ before( :each ) do
7
+ @metric = Hitimes::Metric.new( "testing" )
8
+ end
9
+
10
+ it 'has a name' do
11
+ @metric.name.should == "testing"
12
+ end
13
+
14
+ it "has associated data from initialization" do
15
+ m = Hitimes::Metric.new( "more-data", 'foo' => 'bar', 'this' => 'that' )
16
+ m.additional_data['foo'].should == 'bar'
17
+ m.additional_data['this'].should == 'that'
18
+
19
+ m = Hitimes::Metric.new( "more-data", { 'foo' => 'bar', 'this' => 'that' } )
20
+ m.additional_data['foo'].should == 'bar'
21
+ m.additional_data['this'].should == 'that'
22
+ end
23
+
24
+ it "initially has no sampling times" do
25
+ @metric.sampling_start_time.should == nil
26
+ @metric.sampling_stop_time.should == nil
27
+ end
28
+ end
29
+
30
+
data/spec/stats_spec.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require File.expand_path( File.join( File.dirname( __FILE__ ), "spec_helper.rb" ) )
2
2
 
3
- require 'hitimes_ext'
3
+ require 'hitimes/stats'
4
+ require 'json'
4
5
 
5
6
  describe Hitimes::Stats do
6
7
  before( :each ) do
@@ -46,6 +47,10 @@ describe Hitimes::Stats do
46
47
  @full_stats.stddev.should == 1.0
47
48
  end
48
49
 
50
+ it "calculates the sum of squares " do
51
+ @full_stats.sumsq.should == 14.0
52
+ end
53
+
49
54
  describe "#to_hash " do
50
55
  it "converts to a Hash" do
51
56
  h = @full_stats.to_hash
@@ -66,7 +71,30 @@ describe Hitimes::Stats do
66
71
  it "raises NoMethodError if an invalid stat is used" do
67
72
  lambda { @full_stats.to_hash( "wibble" ) }.should raise_error( NoMethodError )
68
73
  end
69
-
70
74
  end
71
75
 
76
+ describe "#to_json" do
77
+ it "converts to a json string" do
78
+ j = @full_stats.to_json
79
+ h = JSON.parse( j )
80
+ h.size.should == ::Hitimes::Stats::STATS.size
81
+ h.keys.sort.should == ::Hitimes::Stats::STATS
82
+ end
83
+
84
+ it "converts to a limited Hash if given arguments" do
85
+ j = @full_stats.to_json( "min", "max", "mean" )
86
+ h = JSON.parse( j )
87
+ h.size.should == 3
88
+ h.keys.sort.should == %w[ max mean min ]
89
+
90
+ j = @full_stats.to_json( %w[ count rate ] )
91
+ h = JSON.parse( j )
92
+ h.size.should == 2
93
+ h.keys.sort.should == %w[ count rate ]
94
+ end
95
+
96
+ it "raises NoMethodError if an invalid stat is used" do
97
+ lambda { @full_stats.to_json( "wibble" ) }.should raise_error( NoMethodError )
98
+ end
99
+ end
72
100
  end