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

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/HISTORY CHANGED
@@ -1,4 +1,14 @@
1
1
  = Changelog
2
+ == Version 1.0.0 2009-06-12
3
+
4
+ * Major version bump with complete refactor of the metric collection API
5
+ * 3 types of metrics now instead of just 1 Timer
6
+ * ValueMetric
7
+ * TimedMetric
8
+ * TimedValueMetric
9
+ * The ability to convert all metrics #to_hash
10
+ * Updated documentation with examples using each metric type
11
+
2
12
  == Version 0.4.1 2009-02-19
3
13
 
4
14
  * change to ISC License
data/README CHANGED
@@ -15,15 +15,20 @@ Hitimes is a fast, high resolution timer library for recording
15
15
  performance metrics. It uses the appropriate C method calls for each
16
16
  system to get the highest granularity time increments possible.
17
17
 
18
- It currently supports any system with the POSIX call clock_gettime(),
19
- Mac OS X and Windows.
18
+ It currently supports any of the following systems:
20
19
 
21
- Using Hitimes can be faster than using a series of Time.new calls, and
20
+ * any system with the POSIX call <tt>clock_gettime()</tt>,
21
+ * Mac OS X
22
+ * Windows
23
+
24
+ Using Hitimes can be faster than using a series of +Time.new+ calls, and
22
25
  it will have a much higher granularity. It is definitely faster than
23
- using Process.times.
26
+ using +Process.times+.
24
27
 
25
28
  == SYNOPSIS
26
29
 
30
+ === Interval
31
+
27
32
  Use Hitimes::Interval to calculate only the duration of a block of code
28
33
 
29
34
  duration = Hitimes::Interval.measure do
@@ -32,21 +37,76 @@ Use Hitimes::Interval to calculate only the duration of a block of code
32
37
 
33
38
  puts duration
34
39
 
35
- Use a Hitimes::Timer to calculate statistics about an iterative operation
40
+ === TimedMetric
41
+
42
+ Use a Hitimes::TimedMetric to calculate statistics about an iterative operation
43
+
44
+ timed_metric = Hitimes::TimedMetric.new('operation on items')
45
+
46
+ Explicitly use +start+ and +stop+:
36
47
 
37
- timer = Hitimes::Timer.new
38
48
  collection.each do |item|
39
- timer.start
49
+ timed_metric.start
40
50
  # .. do something with item
41
- timer.stop
51
+ timed_metric.stop
52
+ end
53
+
54
+ Or use the block. In TimedMetric the return value of +measure+ is the return
55
+ value of the block
56
+
57
+ collection.each do |item|
58
+ result_of_do_something = timed_metric.measure { do_something( item ) }
42
59
  end
43
60
 
44
- puts timer.mean
45
- puts timer.median
46
- puts timer.max
47
- puts timer.min
48
- puts timer.stddev
49
- puts timer.rate
61
+ And then look at the stats
62
+
63
+ puts timed_metric.mean
64
+ puts timed_metric.max
65
+ puts timed_metric.min
66
+ puts timed_metric.stddev
67
+ puts timed_metric.rate
68
+
69
+ === ValueMetric
70
+
71
+ Use a Hitimes::ValueMetric to calculate statistics about measured samples
72
+
73
+ value_metric = Hitimes::ValueMetric.new( 'size of thing' )
74
+ loop do
75
+ # ... do stuff changing sizes of 'thing'
76
+ value_metric.measure( thing.size )
77
+ # ... do other stuff that may change size of thing
78
+ end
79
+
80
+ puts value_metric.mean
81
+ puts value_metric.max
82
+ puts value_metric.min
83
+ puts value_metric.stddev
84
+ puts value_metric.rate
85
+
86
+
87
+ === TimedValueMetric
88
+
89
+ Use a Hitimes::TimedValueMetric to calculate statistics about batches of samples
90
+
91
+ timed_value_metric = Hitimes::TimedValueMetric.new( 'batch times' )
92
+ loop do
93
+ batch = ... # get a batch of things
94
+ timed_value_metric.start
95
+ # .. do something with batch
96
+ timed_value_metric.stop( batch.size )
97
+ end
98
+
99
+ puts timed_value_metric.rate
100
+
101
+ puts timed_value_metric.timed_stats.mean
102
+ puts timed_value_metric.timed_stats.max
103
+ puts timed_value_metric.timed_stats.min
104
+ puts timed_value_metric.timed_stats.stddev
105
+
106
+ puts timed_value_metric.value_stats.mean
107
+ puts timed_value_metric.value_stats.max
108
+ puts timed_value_metric.value_stats.min
109
+ puts timed_value_metric.value_stats.stddev
50
110
 
51
111
 
52
112
  == CHANGES
@@ -254,6 +254,9 @@ VALUE hitimes_interval_stop_instant( VALUE self )
254
254
  /**
255
255
  * call-seq:
256
256
  * interval.duration -> Float
257
+ * interval.to_f -> Float
258
+ * interval.to_seconds -> Float
259
+ * interval.length -> Float
257
260
  *
258
261
  * Returns the Float value of the interval, the value is in seconds. If the
259
262
  * interval has not had stop called yet, it will report the number of seconds
@@ -321,10 +324,10 @@ void Init_hitimes_interval()
321
324
  rb_define_module_function( cH_Interval, "now", hitimes_interval_now, 0 ); /* in hitimes_interval.c */
322
325
  rb_define_module_function( cH_Interval, "measure", hitimes_interval_measure, 0 ); /* in hitimes_interval.c */
323
326
 
324
- rb_define_method( cH_Interval, "to_f", hitimes_interval_duration, 0 ); /* in hitimes_interval.c */
325
- rb_define_method( cH_Interval, "to_seconds", hitimes_interval_duration, 0 ); /* in hitimes_interval.c */
326
327
  rb_define_method( cH_Interval, "duration", hitimes_interval_duration, 0 ); /* in hitimes_interval.c */
327
- rb_define_method( cH_Interval, "length", hitimes_interval_duration, 0 ); /* in hitimes_interval.c */
328
+ rb_define_method( cH_Interval, "length", hitimes_interval_duration, 0 );
329
+ rb_define_method( cH_Interval, "to_f", hitimes_interval_duration, 0 );
330
+ rb_define_method( cH_Interval, "to_seconds", hitimes_interval_duration, 0 );
328
331
 
329
332
  rb_define_method( cH_Interval, "started?", hitimes_interval_started, 0 ); /* in hitimes_interval.c */
330
333
  rb_define_method( cH_Interval, "running?", hitimes_interval_running, 0 ); /* in hitimes_interval.c */
data/ext/hitimes_stats.c CHANGED
@@ -39,9 +39,10 @@ VALUE hitimes_stats_alloc(VALUE klass)
39
39
 
40
40
  /**
41
41
  * call-seq:
42
- * stat.update( val ) -> nil
42
+ * stat.update( val ) -> val
43
43
  *
44
44
  * Update the running stats with the new value.
45
+ * Return the input value.
45
46
  */
46
47
  VALUE hitimes_stats_update( VALUE self, VALUE v )
47
48
  {
@@ -62,7 +63,7 @@ VALUE hitimes_stats_update( VALUE self, VALUE v )
62
63
  stats->sum += new_v;
63
64
  stats->sumsq += ( new_v * new_v );
64
65
 
65
- return Qnil;
66
+ return v;
66
67
  }
67
68
 
68
69
  /**
@@ -91,10 +92,15 @@ VALUE hitimes_stats_mean( VALUE self )
91
92
  * call-seq:
92
93
  * stat.rate -> Float
93
94
  *
94
- * Return the count per sum. In many cases when Stats#update( _value_ ) is
95
- * called, the _value_ is a unit of time, typically seconds. #rate
96
- * is a convenience for those times. In the most common case, where _value_
97
- * is in seconds, then #rate returns the count / second.
95
+ * Return the +count+ divided by +sum+.
96
+ *
97
+ * In many cases when Stats#update( _value_ ) is called, the _value_ is a unit
98
+ * of time, typically seconds or microseconds. #rate is a convenience for those
99
+ * times. In this case, where _value_ is a unit if time, then count divided by
100
+ * sum is a useful value, i.e. +something per unit of time+.
101
+ *
102
+ * In the case where _value_ is a non-time related value, then the value
103
+ * returned by _rate_ is not really useful.
98
104
  *
99
105
  */
100
106
  VALUE hitimes_stats_rate( VALUE self )
@@ -176,6 +182,22 @@ VALUE hitimes_stats_sum( VALUE self )
176
182
  return rb_float_new( stats->sum );
177
183
  }
178
184
 
185
+ /**
186
+ * call-seq:
187
+ * stat.sumsq -> Float
188
+ *
189
+ * Return the sum of the squars of all the values that passed through the Stats
190
+ * object.
191
+ */
192
+ VALUE hitimes_stats_sumsq( VALUE self )
193
+ {
194
+ hitimes_stats_t *stats;
195
+
196
+ Data_Get_Struct( self, hitimes_stats_t, stats );
197
+
198
+ return rb_float_new( stats->sumsq );
199
+ }
200
+
179
201
 
180
202
  /**
181
203
  * call-seq:
@@ -205,8 +227,8 @@ VALUE hitimes_stats_stddev ( VALUE self )
205
227
  * The Stats class encapulsates capturing and reporting statistics. It is
206
228
  * modeled after the RFuzz::Sampler class, but implemented in C. For general use
207
229
  * you allocate a new Stats object, and then update it with new values. The
208
- * Stats object will keep track of the _min_, _max_, _count_ and _sum_ and when
209
- * you want you may also retrieve the _mean_, _stddev_ and _rate_.
230
+ * Stats object will keep track of the _min_, _max_, _count_, _sum_ and _sumsq_
231
+ * and when you want you may also retrieve the _mean_, _stddev_ and _rate_.
210
232
  *
211
233
  * this contrived example shows getting a list of all the files in a directory
212
234
  * and running stats on file sizes.
@@ -240,6 +262,7 @@ void Init_hitimes_stats()
240
262
  rb_define_method( cH_Stats, "min", hitimes_stats_min, 0 ); /* in hitimes_stats.c */
241
263
  rb_define_method( cH_Stats, "rate", hitimes_stats_rate, 0 ); /* in hitimes_stats.c */
242
264
  rb_define_method( cH_Stats, "sum", hitimes_stats_sum, 0 ); /* in hitimes_stats.c */
265
+ rb_define_method( cH_Stats, "sumsq", hitimes_stats_sumsq, 0 ); /* in hitimes_stats.c */
243
266
  rb_define_method( cH_Stats, "stddev", hitimes_stats_stddev, 0 ); /* in hitimes_stats.c */
244
267
  }
245
268
 
data/gemspec.rb CHANGED
@@ -20,8 +20,10 @@ Hitimes::GEM_SPEC = Gem::Specification.new do |spec|
20
20
  spec.executables = pkg.files.bin.collect { |b| File.basename(b) }
21
21
 
22
22
  # add dependencies here
23
- spec.add_dependency("rake", ">= 0.8.1")
24
- spec.add_dependency("configuration", ">= 0.0.5")
23
+ spec.add_dependency("rake", "~> 0.8.1")
24
+ spec.add_dependency("configuration", " ~> 0.0.5")
25
+
26
+ spec.add_development_dependency( "json", "~> 1.1.3")
25
27
 
26
28
  if ext_conf = Configuration.for_if_exist?("extension") then
27
29
  spec.extensions << ext_conf.configs
data/lib/hitimes.rb CHANGED
@@ -19,6 +19,10 @@ end
19
19
  require 'hitimes/paths'
20
20
  require 'hitimes/version'
21
21
  require 'hitimes/stats'
22
+ require 'hitimes_ext'
22
23
  require 'hitimes/mutexed_stats'
23
- require 'hitimes/timer'
24
+ require 'hitimes/metric'
25
+ require 'hitimes/value_metric'
26
+ require 'hitimes/timed_metric'
27
+ require 'hitimes/timed_value_metric'
24
28
 
@@ -0,0 +1,74 @@
1
+ module Hitimes
2
+ #
3
+ # Metric hold the common meta information for all derived metric classes
4
+ #
5
+ # All metrics hold the meta information of:
6
+ #
7
+ # * The name of the metric
8
+ # * The time of day the first measurement is taken
9
+ # * The time of day the last measurement is taken
10
+ # * additional data
11
+ #
12
+ # Each derived class is assumed to set the sampling_start_time and
13
+ # sampling_stop_time appropriately.
14
+ #
15
+ # Metric itself should generally not be used. Only use the derived classes.
16
+ #
17
+ class Metric
18
+
19
+ # the time at which the first sample was taken
20
+ # This is the number of microseconds since UNIX epoch UTC as a Float
21
+ attr_accessor :sampling_start_time
22
+
23
+ # the time at which the last sample was taken.
24
+ # This is the number of microseconds since UNIX epoch UTC as a Float
25
+ attr_accessor :sampling_stop_time
26
+
27
+ # An additional hash of data to associate with the metric
28
+ attr_reader :additional_data
29
+
30
+ # The 'name' to associate with the metric
31
+ attr_reader :name
32
+
33
+ #
34
+ # :call-seq:
35
+ # Metric.new( 'my_metric' ) -> Metric
36
+ # Metric.new( 'my_metric', 'foo' => 'bar', 'this' => 42 ) -> Metric
37
+ #
38
+ # Create a new ValueMetric giving it a name and additional data.
39
+ #
40
+ # +additional_data+ may be anything that follows the +to_hash+ protocol.
41
+ # +name+ may be anything that follows the +to_s+ protocol.
42
+ #
43
+ def initialize( name, additional_data = {} )
44
+ @sampling_start_time = nil
45
+ @sampling_stop_time = nil
46
+ @name = name.to_s
47
+ @additional_data = additional_data.to_hash
48
+ end
49
+
50
+ #
51
+ # :call-seq:
52
+ # metric.to_hash -> Hash
53
+ # metric.to_hash
54
+ #
55
+ # Convert the metric to a Hash.
56
+ #
57
+ def to_hash
58
+ { 'sampling_start_time' => @sampling_start_time,
59
+ 'sampling_stop_time' => @sampling_stop_time,
60
+ 'additional_data' => @additional_data,
61
+ 'name' => @name }
62
+ end
63
+
64
+ #
65
+ # :call-seq:
66
+ # metric.utc_microseconds -> Float
67
+ #
68
+ # The current time in microseconds from the UNIX Epoch in the UTC
69
+ #
70
+ def utc_microseconds
71
+ Time.now.gmtime.to_f * 1_000_000
72
+ end
73
+ end
74
+ end
data/lib/hitimes/stats.rb CHANGED
@@ -1,7 +1,9 @@
1
+ require 'hitimes_ext'
2
+ require 'stringio'
1
3
  module Hitimes
2
4
  class Stats
3
5
  # A list of the available stats
4
- STATS = %w[ count max mean min rate stddev sum ]
6
+ STATS = %w[ count max mean min rate stddev sum sumsq ]
5
7
 
6
8
  #
7
9
  # call-seq:
@@ -25,5 +27,28 @@ module Hitimes
25
27
  return h
26
28
  end
27
29
 
30
+ #
31
+ # call-seq:
32
+ # stat.to_json -> String
33
+ # stat.to_json( *args ) -> String
34
+ #
35
+ # return a json string of the stats. By default this returns a json string
36
+ # of all the stats. If an array of items is passed in, those that match the
37
+ # known stats will be all that is included in the json output.
38
+ #
39
+ def to_json( *args )
40
+ h = to_hash( *args )
41
+ a = []
42
+ s = StringIO.new
43
+
44
+ s.print "{ "
45
+ h.each_pair do |k,v|
46
+ a << "\"#{k}\": #{v}"
47
+ end
48
+ s.print a.join(", ")
49
+ s.print "}"
50
+ return s.string
51
+ end
52
+
28
53
  end
29
54
  end
@@ -0,0 +1,181 @@
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
+ require 'forwardable'
8
+ module Hitimes
9
+ #
10
+ # A TimedMetric holds the metrics on how long it takes to do something. For
11
+ # example, measuring how long a method takes to operate.
12
+ #
13
+ # tm = TimedMetric.new( 'my-method' )
14
+ #
15
+ # 200.times do
16
+ # my_method_result = tm.measure do
17
+ # my_method( ... )
18
+ # end
19
+ # end
20
+ #
21
+ # puts "#{ tm.name } operated at a rate of #{ tm.rate } calls per second"
22
+ #
23
+ # Since TimedMetric is a child class of Metric make sure to look at the
24
+ # Metric API also.
25
+ #
26
+ # A TimedMetric measures the execution time of an option with the Interval
27
+ # class.
28
+ #
29
+ # A TimedMetric contains a Stats object, therefore TimedMetric has +count+, +max+,
30
+ # +mean+, +min+, +rate+, +stddev+, +sum+, +sumsq+ methods that delegate to that Stats
31
+ # object for convenience.
32
+ #
33
+ #
34
+ class TimedMetric < Metric
35
+ # holds all the statistics
36
+ attr_reader :stats
37
+
38
+ class << TimedMetric
39
+ #
40
+ # :call-seq:
41
+ # TimedMetric.now -> TimedMetric
42
+ #
43
+ # Return a TimedMetric that has been started
44
+ #
45
+ def now( name, additional_data = {} )
46
+ t = TimedMetric.new( name, additional_data )
47
+ t.start
48
+ return t
49
+ end
50
+ end
51
+
52
+ #
53
+ # :call-seq:
54
+ # TimedMetric.new( 'name') -> TimedMetric
55
+ # TimedMetric.new( 'name', 'other' => 'data') -> TimedMetric
56
+ #
57
+ # Create a new TimedMetric 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
+ @stats = Stats.new
63
+ @current_interval = nil
64
+ end
65
+
66
+ #
67
+ # :call-seq:
68
+ # timed_metric.current_interval -> Interval
69
+ #
70
+ # Return the current interval, if one doesn't exist create one.
71
+ #
72
+ def current_interval
73
+ @current_interval ||= Interval.new
74
+ end
75
+
76
+ #
77
+ # :call-seq:
78
+ # timed_metric.running? -> true or false
79
+ #
80
+ # return whether or not the timer is currently running.
81
+ #
82
+ def running?
83
+ current_interval.running?
84
+ end
85
+
86
+ #
87
+ # :call-seq:
88
+ # timed_metric.start -> nil
89
+ #
90
+ # Start the current metric, if the current metric is already started, then
91
+ # this is a noop.
92
+ #
93
+ def start
94
+ current_interval.start unless running?
95
+ @sampling_start_time ||= self.utc_microseconds()
96
+ nil
97
+ end
98
+
99
+ #
100
+ # :call-seq:
101
+ # timed_metric.stop -> Float or nil
102
+ #
103
+ # Stop the current metric. This updates the stats and removes the current
104
+ # interval. If the timer was stopped then the duration of the last Interval
105
+ # is returned. If the timer was already stopped then false is returned and
106
+ # no stats are updated.
107
+ #
108
+ def stop
109
+ if running? then
110
+ d = current_interval.stop
111
+ @current_interval = nil
112
+ @sampling_stop_time = self.utc_microseconds()
113
+ @stats.update( d )
114
+ return d
115
+ end
116
+ return false
117
+ end
118
+
119
+ #
120
+ # :call-seq:
121
+ # timed_metric.measure { ... } -> Object
122
+ #
123
+ # Measure the execution of a block and add those stats to the running stats.
124
+ # The return value is the return value of the block
125
+ #
126
+ def measure( &block )
127
+ return_value = nil
128
+ begin
129
+ start
130
+ return_value = yield
131
+ ensure
132
+ stop
133
+ end
134
+ return return_value
135
+ end
136
+
137
+ #
138
+ # :call-seq:
139
+ # timed_metric.split -> Float
140
+ #
141
+ # Split the current TimedMetric. Essentially, mark a split time. This means
142
+ # stop the current interval and create a new interval, but make sure
143
+ # that the new interval lines up exactly, timewise, behind the previous
144
+ # interval.
145
+ #
146
+ # If the timer is running, then split returns the duration of the previous
147
+ # interval, i.e. the split-time. If the timer is not running, nothing
148
+ # happens and false is returned.
149
+ #
150
+ def split
151
+ if running? then
152
+ next_interval = current_interval.split
153
+ d = current_interval.duration
154
+ @stats.update( d )
155
+ @current_interval = next_interval
156
+ return d
157
+ end
158
+ return false
159
+ end
160
+
161
+ #
162
+ # :call-seq:
163
+ # metric.to_hash -> Hash
164
+ #
165
+ # Convert the metric to a hash
166
+ #
167
+ def to_hash
168
+ h = super
169
+ Stats::STATS.each do |s|
170
+ h[s] = self.send( s )
171
+ end
172
+ return h
173
+ end
174
+
175
+
176
+ # forward appropriate calls directly to the stats object
177
+ extend Forwardable
178
+ def_delegators :@stats, :count, :sum, :max, :mean, :min, :rate, :stddev, :sum, :sumsq
179
+ alias :duration :sum
180
+ end
181
+ end