hitimes 1.3.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +1 -12
  3. data/HISTORY.md +26 -2
  4. data/Manifest.txt +5 -31
  5. data/README.md +44 -59
  6. data/hitimes.gemspec +26 -0
  7. data/lib/hitimes/initialize.rb +104 -0
  8. data/lib/hitimes/instant.rb +41 -0
  9. data/lib/hitimes/interval.rb +171 -0
  10. data/lib/hitimes/metric.rb +18 -22
  11. data/lib/hitimes/mutexed_stats.rb +3 -20
  12. data/lib/hitimes/paths.rb +16 -14
  13. data/lib/hitimes/stats.rb +119 -22
  14. data/lib/hitimes/timed_metric.rb +43 -42
  15. data/lib/hitimes/timed_value_metric.rb +43 -43
  16. data/lib/hitimes/value_metric.rb +16 -15
  17. data/lib/hitimes/version.rb +3 -1
  18. data/lib/hitimes.rb +14 -41
  19. metadata +24 -157
  20. data/Rakefile +0 -28
  21. data/examples/benchmarks.rb +0 -113
  22. data/examples/stats.rb +0 -31
  23. data/ext/hitimes/c/extconf.rb +0 -24
  24. data/ext/hitimes/c/hitimes.c +0 -37
  25. data/ext/hitimes/c/hitimes_instant_clock_gettime.c +0 -28
  26. data/ext/hitimes/c/hitimes_instant_osx.c +0 -48
  27. data/ext/hitimes/c/hitimes_instant_windows.c +0 -27
  28. data/ext/hitimes/c/hitimes_interval.c +0 -370
  29. data/ext/hitimes/c/hitimes_interval.h +0 -73
  30. data/ext/hitimes/c/hitimes_stats.c +0 -269
  31. data/ext/hitimes/c/hitimes_stats.h +0 -30
  32. data/ext/hitimes/java/src/hitimes/Hitimes.java +0 -63
  33. data/ext/hitimes/java/src/hitimes/HitimesInterval.java +0 -176
  34. data/ext/hitimes/java/src/hitimes/HitimesService.java +0 -16
  35. data/ext/hitimes/java/src/hitimes/HitimesStats.java +0 -112
  36. data/spec/hitimes_spec.rb +0 -24
  37. data/spec/interval_spec.rb +0 -136
  38. data/spec/metric_spec.rb +0 -28
  39. data/spec/mutex_stats_spec.rb +0 -36
  40. data/spec/paths_spec.rb +0 -11
  41. data/spec/spec_helper.rb +0 -11
  42. data/spec/stats_spec.rb +0 -98
  43. data/spec/timed_metric_spec.rb +0 -155
  44. data/spec/timed_value_metric_spec.rb +0 -171
  45. data/spec/value_metric_spec.rb +0 -108
  46. data/spec/version_spec.rb +0 -7
  47. data/tasks/default.rake +0 -242
  48. data/tasks/extension.rake +0 -38
  49. data/tasks/this.rb +0 -208
  50. /data/{LICENSE → LICENSE.txt} +0 -0
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  #--
3
4
  # Copyright (c) 2008, 2009 Jeremy Hinegardner
@@ -13,15 +14,14 @@ module Hitimes
13
14
  # * The name of the metric
14
15
  # * The time of day the first measurement is taken
15
16
  # * The time of day the last measurement is taken
16
- # * additional data
17
+ # * additional data
17
18
  #
18
19
  # Each derived class is assumed to set the sampling_start_time and
19
20
  # sampling_stop_time appropriately.
20
- #
21
+ #
21
22
  # Metric itself should generally not be used. Only use the derived classes.
22
23
  #
23
24
  class Metric
24
-
25
25
  # the number of seconds as a float since the sampling_start_time
26
26
  attr_reader :sampling_delta
27
27
 
@@ -41,7 +41,7 @@ module Hitimes
41
41
  # +additional_data+ may be anything that follows the +to_hash+ protocol.
42
42
  # +name+ may be anything that follows the +to_s+ protocol.
43
43
  #
44
- def initialize( name, additional_data = {} )
44
+ def initialize(name, additional_data = {})
45
45
  @sampling_start_time = nil
46
46
  @sampling_start_interval = nil
47
47
  @sampling_delta = 0
@@ -51,7 +51,7 @@ module Hitimes
51
51
  end
52
52
 
53
53
  #
54
- # :call-seq:
54
+ # :call-seq:
55
55
  # metric.sampling_start_time -> Float or nil
56
56
  #
57
57
  # The time at which the first sample was taken.
@@ -60,11 +60,9 @@ module Hitimes
60
60
  # If the metric has not started measuring then the start time is nil.
61
61
  #
62
62
  def sampling_start_time
63
- if @sampling_start_interval then
64
- @sampling_start_time ||= self.utc_microseconds()
65
- else
66
- nil
67
- end
63
+ return unless @sampling_start_interval
64
+
65
+ @sampling_start_time ||= utc_microseconds
68
66
  end
69
67
 
70
68
  #
@@ -73,8 +71,8 @@ module Hitimes
73
71
  #
74
72
  # The time at which the last sample was taken
75
73
  # This is the number of microseconds since UNIX epoch UTC as a Float
76
- #
77
- # If the metric has not completely measured at least one thing then
74
+ #
75
+ # If the metric has not completely measured at least one thing then
78
76
  # stop time is nil.
79
77
  #
80
78
  # Because accessing the actual 'time of day' is an expesive operation, we
@@ -84,11 +82,9 @@ module Hitimes
84
82
  # When sampling_stop_time is called, the actual time of day is caculated.
85
83
  #
86
84
  def sampling_stop_time
87
- if @sampling_delta > 0 then
88
- (self.sampling_start_time + (@sampling_delta * 1_000_000))
89
- else
90
- nil
91
- end
85
+ return unless @sampling_delta.positive?
86
+
87
+ (sampling_start_time + (@sampling_delta * 1_000_000))
92
88
  end
93
89
 
94
90
  #
@@ -96,13 +92,13 @@ module Hitimes
96
92
  # metric.to_hash -> Hash
97
93
  # metric.to_hash
98
94
  #
99
- # Convert the metric to a Hash.
95
+ # Convert the metric to a Hash.
100
96
  #
101
97
  def to_hash
102
- { 'sampling_start_time' => self.sampling_start_time,
103
- 'sampling_stop_time' => self.sampling_stop_time,
104
- 'additional_data' => self.additional_data,
105
- 'name' => self.name }
98
+ { "sampling_start_time" => sampling_start_time,
99
+ "sampling_stop_time" => sampling_stop_time,
100
+ "additional_data" => additional_data,
101
+ "name" => name, }
106
102
  end
107
103
 
108
104
  #
@@ -1,32 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #--
2
4
  # Copyright (c) 2008, 2009 Jeremy Hinegardner
3
5
  # All rights reserved. See LICENSE and/or COPYING for details.
4
6
  #++
5
7
 
6
- require 'thread'
7
-
8
8
  module Hitimes
9
9
  #
10
10
  # MutexedStats is the start of a threadsafe Stats class. Currently, on MRI
11
11
  # Ruby the Stats object is already threadsafe, so there is no need to use
12
12
  # MutexedStats.
13
13
  #
14
- class MutexedStats < Stats
15
- def initialize
16
- @mutex = Mutex.new
17
- end
18
-
19
- # call-seq:
20
- # mutex_stat.update( val ) -> nil
21
- #
22
- # Update the running stats with the new value in a threadsafe manner.
23
- #
24
- def update( value )
25
- @mutex.synchronize do
26
- super( value )
27
- end
28
- end
29
- end
14
+ MutexedStats = Stats
30
15
  end
31
-
32
-
data/lib/hitimes/paths.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #--
2
4
  # Copyright (c) 2008 Jeremy Hinegardner
3
5
  # All rights reserved. See LICENSE and/or COPYING for details.
@@ -8,34 +10,34 @@ module Hitimes
8
10
  # Access to various paths inside the project programatically
9
11
  #
10
12
  module Paths
11
- #
13
+ #
12
14
  # :call-seq:
13
15
  # Hitimes::Paths.root_dir -> String
14
16
  #
15
17
  # Returns The full expanded path of the parent directory of +lib+
16
- # going up the path from the current file. A trailing File::SEPARATOR
18
+ # going up the path from the current file. A trailing File::SEPARATOR
17
19
  # is guaranteed.
18
- #
20
+ #
19
21
  def self.root_dir
20
- @root_dir ||=(
22
+ @root_dir ||= begin
21
23
  path_parts = ::File.expand_path(__FILE__).split(::File::SEPARATOR)
22
24
  lib_index = path_parts.rindex("lib")
23
25
  @root_dir = path_parts[0...lib_index].join(::File::SEPARATOR) + ::File::SEPARATOR
24
- )
25
- end
26
+ end
27
+ end
26
28
 
27
- #
29
+ #
28
30
  # :call-seq:
29
31
  # Hitimes::Paths.lib_path( *args ) -> String
30
32
  #
31
33
  # Returns The full expanded path of the +lib+ directory below
32
- # _root_dir_. All parameters passed in are joined onto the
33
- # result. A trailing File::SEPARATOR is guaranteed if
34
+ # _root_dir_. All parameters passed in are joined onto the
35
+ # result. A trailing File::SEPARATOR is guaranteed if
34
36
  # _args_ are *not* present.
35
- #
37
+ #
36
38
  def self.lib_path(*args)
37
- self.sub_path("lib", *args)
38
- end
39
+ sub_path("lib", *args)
40
+ end
39
41
 
40
42
  #
41
43
  # :call-seq:
@@ -45,9 +47,9 @@ module Hitimes
45
47
  # _arg_ parameters passed in are joined onto the result. A trailing
46
48
  # File::SEPARATOR is guaranteed if _args_ are *not* present.
47
49
  #
48
- def self.sub_path(sub,*args)
50
+ def self.sub_path(sub, *args)
49
51
  sp = ::File.join(root_dir, sub) + File::SEPARATOR
50
- sp = ::File.join(sp, *args) if args
52
+ ::File.join(sp, *args) if args
51
53
  end
52
54
  end
53
55
  end
data/lib/hitimes/stats.rb CHANGED
@@ -1,34 +1,132 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #--
2
4
  # Copyright (c) 2008, 2009 Jeremy Hinegardner
3
5
  # All rights reserved. See LICENSE and/or COPYING for details.
4
6
  #++
5
7
 
6
- require 'stringio'
8
+ require "stringio"
7
9
  module Hitimes
10
+ #
11
+ # The Stats class encapulsates capturing and reporting statistics. It is
12
+ # modeled after the RFuzz::Sampler class, but implemented in C. For general use
13
+ # you allocate a new Stats object, and then update it with new values. The
14
+ # Stats object will keep track of the _min_, _max_, _count_, _sum_ and _sumsq_
15
+ # and when you want you may also retrieve the _mean_, _stddev_ and _rate_.
16
+ #
17
+ # this contrived example shows getting a list of all the files in a directory
18
+ # and running stats on file sizes.
19
+ #
20
+ # s = Hitimes::Stats.new
21
+ # dir = ARGV.shift || Dir.pwd
22
+ # Dir.entries( dir ).each do |entry|
23
+ # fs = File.stat( entry )
24
+ # if fs.file? then
25
+ # s.update( fs.size )
26
+ # end
27
+ # end
28
+ #
29
+ # %w[ count min max mean sum stddev rate ].each do |m|
30
+ # puts "#{m.rjust(6)} : #{s.send( m ) }"
31
+ # end
32
+ #
8
33
  class Stats
9
34
  # A list of the available stats
10
- STATS = %w[ count max mean min rate stddev sum sumsq ]
35
+ STATS = %w[count max mean min rate stddev sum sumsq].freeze
36
+
37
+ attr_reader :min, :max, :count, :sum, :sumsq
38
+
39
+ def initialize
40
+ @mutex = Mutex.new
41
+ @min = Float::INFINITY
42
+ @max = -Float::INFINITY
43
+ @count = 0
44
+ @sum = 0.0
45
+ @sumsq = 0.0
46
+ end
11
47
 
12
- #
48
+ # call-seq:
49
+ # stat.update( val ) -> val
50
+ #
51
+ # Update the running stats with the new value.
52
+ # Return the input value.
53
+ def update(value)
54
+ @mutex.synchronize do
55
+ @min = (value < @min) ? value : @min
56
+ @max = (value > @max) ? value : @max
57
+
58
+ @count += 1
59
+ @sum += value
60
+ @sumsq += (value * value)
61
+ end
62
+
63
+ value
64
+ end
65
+
66
+ # call-seq:
67
+ # stat.mean -> Float
68
+ #
69
+ # Return the arithmetic mean of the values put into the Stats object. If no
70
+ # values have passed through the stats object then 0.0 is returned;
71
+ def mean
72
+ return 0.0 if @count.zero?
73
+
74
+ @sum / @count
75
+ end
76
+
77
+ # call-seq:
78
+ # stat.rate -> Float
79
+ #
80
+ # Return the +count+ divided by +sum+.
81
+ #
82
+ # In many cases when Stats#update( _value_ ) is called, the _value_ is a unit
83
+ # of time, typically seconds or microseconds. #rate is a convenience for those
84
+ # times. In this case, where _value_ is a unit if time, then count divided by
85
+ # sum is a useful value, i.e. +something per unit of time+.
86
+ #
87
+ # In the case where _value_ is a non-time related value, then the value
88
+ # returned by _rate_ is not really useful.
89
+ #
90
+ def rate
91
+ return 0.0 if @sum.zero?
92
+
93
+ @count / @sum
94
+ end
95
+
96
+ #
97
+ # call-seq:
98
+ # stat.stddev -> Float
99
+ #
100
+ # Return the standard deviation of all the values that have passed through the
101
+ # Stats object. The standard deviation has no meaning unless the count is > 1,
102
+ # therefore if the current _stat.count_ is < 1 then 0.0 will be returned;
103
+ #
104
+ def stddev
105
+ return 0.0 unless @count > 1
106
+
107
+ Math.sqrt((@sumsq - ((@sum * @sum) / @count)) / (@count - 1))
108
+ end
109
+
110
+ #
13
111
  # call-seq:
14
112
  # stat.to_hash -> Hash
15
113
  # stat.to_hash( %w[ count max mean ]) -> Hash
16
114
  #
17
115
  # return a hash of the stats. By default this returns a hash of all stats
18
116
  # but passing in an array of items will limit the stats returned to only
19
- # those in the Array.
117
+ # those in the Array.
20
118
  #
21
119
  # If passed in an empty array or nil to to_hash then STATS is assumed to be
22
120
  # the list of stats to return in the hash.
23
121
  #
24
- def to_hash( *args )
25
- h = {}
26
- args = [ args ].flatten
27
- args = STATS if args.empty?
28
- args.each do |meth|
29
- h[meth] = self.send( meth )
122
+ def to_hash(*args)
123
+ result = {}
124
+ fields = [args].flatten
125
+ fields = STATS if fields.empty?
126
+ fields.each do |meth|
127
+ result[meth] = send(meth)
30
128
  end
31
- return h
129
+ result
32
130
  end
33
131
 
34
132
  #
@@ -40,19 +138,18 @@ module Hitimes
40
138
  # of all the stats. If an array of items is passed in, those that match the
41
139
  # known stats will be all that is included in the json output.
42
140
  #
43
- def to_json( *args )
44
- h = to_hash( *args )
45
- a = []
46
- s = StringIO.new
141
+ def to_json(*args)
142
+ stats = to_hash(*args)
143
+ slugs = []
144
+ out = StringIO.new
47
145
 
48
- s.print "{ "
49
- h.each_pair do |k,v|
50
- a << "\"#{k}\": #{v}"
146
+ out.print "{ "
147
+ stats.each_pair do |key, val|
148
+ slugs << "\"#{key}\": #{val}"
51
149
  end
52
- s.print a.join(", ")
53
- s.print "}"
54
- return s.string
150
+ out.print slugs.join(", ")
151
+ out.print "}"
152
+ out.string
55
153
  end
56
-
57
154
  end
58
155
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  #--
2
4
  # Copyright (c) 2008, 2009 Jeremy Hinegardner
3
5
  # All rights reserved. See LICENSE and/or COPYING for details.
4
6
  #++
5
7
 
6
- require 'forwardable'
8
+ require "forwardable"
7
9
  module Hitimes
8
10
  #
9
11
  # A TimedMetric holds the metrics on how long it takes to do something. For
@@ -11,11 +13,11 @@ module Hitimes
11
13
  #
12
14
  # tm = TimedMetric.new( 'my-method' )
13
15
  #
14
- # 200.times do
15
- # my_method_result = tm.measure do
16
+ # 200.times do
17
+ # my_method_result = tm.measure do
16
18
  # my_method( ... )
17
19
  # end
18
- # end
20
+ # end
19
21
  #
20
22
  # puts "#{ tm.name } operated at a rate of #{ tm.rate } calls per second"
21
23
  #
@@ -23,9 +25,9 @@ module Hitimes
23
25
  # Metric API also.
24
26
  #
25
27
  # 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+,
28
+ # class.
29
+ #
30
+ # A TimedMetric contains a Stats object, therefore TimedMetric has +count+, +max+,
29
31
  # +mean+, +min+, +rate+, +stddev+, +sum+, +sumsq+ methods that delegate to that Stats
30
32
  # object for convenience.
31
33
  #
@@ -41,10 +43,10 @@ module Hitimes
41
43
  #
42
44
  # Return a TimedMetric that has been started
43
45
  #
44
- def now( name, additional_data = {} )
45
- t = TimedMetric.new( name, additional_data )
46
- t.start
47
- return t
46
+ def now(name, additional_data = {})
47
+ tm = TimedMetric.new(name, additional_data)
48
+ tm.start
49
+ tm
48
50
  end
49
51
  end
50
52
 
@@ -56,8 +58,8 @@ module Hitimes
56
58
  # Create a new TimedMetric giving it a name and additional data.
57
59
  # +additional_data+ may be anything that follows the +to_hash+ protocol
58
60
  #
59
- def initialize( name, additional_data = {} )
60
- super( name, additional_data )
61
+ def initialize(name, additional_data = {})
62
+ super(name, additional_data)
61
63
  @stats = Stats.new
62
64
  @current_interval = Interval.new
63
65
  end
@@ -66,23 +68,23 @@ module Hitimes
66
68
  # :call-seq:
67
69
  # timed_metric.running? -> true or false
68
70
  #
69
- # return whether or not the timer is currently running.
71
+ # return whether or not the timer is currently running.
70
72
  #
71
73
  def running?
72
74
  @current_interval.running?
73
75
  end
74
76
 
75
- #
77
+ #
76
78
  # :call-seq:
77
79
  # timed_metric.start -> nil
78
80
  #
79
81
  # Start the current metric, if the current metric is already started, then
80
- # this is a noop.
82
+ # this is a noop.
81
83
  #
82
84
  def start
83
- if not @current_interval.running? then
84
- @current_interval.start
85
- @sampling_start_time ||= self.utc_microseconds()
85
+ unless @current_interval.running?
86
+ @current_interval.start
87
+ @sampling_start_time ||= utc_microseconds
86
88
  @sampling_start_interval ||= Interval.now
87
89
  end
88
90
  nil
@@ -96,19 +98,19 @@ module Hitimes
96
98
  # interval. If the timer was stopped then the duration of the last Interval
97
99
  # is returned. If the timer was already stopped then false is returned and
98
100
  # no stats are updated.
99
- #
101
+ #
100
102
  def stop
101
- if @current_interval.running? then
102
- d = @current_interval.stop
103
- @stats.update( d )
103
+ if @current_interval.running?
104
+ duration = @current_interval.stop
105
+ @stats.update(duration)
104
106
  @current_interval = Interval.new
105
107
 
106
108
  # update the length of time we have been sampling
107
109
  @sampling_delta = @sampling_start_interval.duration_so_far
108
110
 
109
- return d
111
+ return duration
110
112
  end
111
- return false
113
+ false
112
114
  end
113
115
 
114
116
  #
@@ -118,7 +120,7 @@ module Hitimes
118
120
  # Measure the execution of a block and add those stats to the running stats.
119
121
  # The return value is the return value of the block
120
122
  #
121
- def measure( &block )
123
+ def measure
122
124
  return_value = nil
123
125
  begin
124
126
  start
@@ -126,7 +128,7 @@ module Hitimes
126
128
  ensure
127
129
  stop
128
130
  end
129
- return return_value
131
+ return_value
130
132
  end
131
133
 
132
134
  #
@@ -142,35 +144,34 @@ module Hitimes
142
144
  # interval, i.e. the split-time. If the timer is not running, nothing
143
145
  # happens and false is returned.
144
146
  #
145
- def split
146
- if @current_interval.running? then
147
+ def split
148
+ if @current_interval.running?
147
149
  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
150
+ duration = @current_interval.duration
151
+ @stats.update(duration)
152
+ @current_interval = next_interval
153
+ return duration
154
+ end
155
+ false
154
156
  end
155
157
 
156
158
  #
157
159
  # :call-seq:
158
160
  # metric.to_hash -> Hash
159
- #
161
+ #
160
162
  # Convert the metric to a hash
161
163
  #
162
164
  def to_hash
163
- h = super
164
- Stats::STATS.each do |s|
165
- h[s] = self.send( s )
165
+ result = super
166
+ Stats::STATS.each do |stat|
167
+ result[stat] = send(stat)
166
168
  end
167
- return h
169
+ result
168
170
  end
169
171
 
170
-
171
172
  # forward appropriate calls directly to the stats object
172
173
  extend Forwardable
173
174
  def_delegators :@stats, :count, :max, :mean, :min, :rate, :stddev, :sum, :sumsq
174
- alias :duration :sum
175
+ alias duration sum
175
176
  end
176
177
  end