hitimes 1.0.4-x86-mswin32

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.
Files changed (46) hide show
  1. data/HISTORY +60 -0
  2. data/LICENSE +13 -0
  3. data/README +134 -0
  4. data/Rakefile +66 -0
  5. data/examples/benchmarks.rb +113 -0
  6. data/examples/stats.rb +31 -0
  7. data/ext/hitimes/extconf.rb +17 -0
  8. data/ext/hitimes/hitimes_ext.c +21 -0
  9. data/ext/hitimes/hitimes_instant_clock_gettime.c +28 -0
  10. data/ext/hitimes/hitimes_instant_osx.c +16 -0
  11. data/ext/hitimes/hitimes_instant_windows.c +27 -0
  12. data/ext/hitimes/hitimes_interval.c +362 -0
  13. data/ext/hitimes/hitimes_interval.h +73 -0
  14. data/ext/hitimes/hitimes_stats.c +269 -0
  15. data/ext/hitimes/hitimes_stats.h +30 -0
  16. data/gemspec.rb +60 -0
  17. data/lib/hitimes.rb +31 -0
  18. data/lib/hitimes/1.8/hitimes_ext.so +0 -0
  19. data/lib/hitimes/1.9/hitimes_ext.so +0 -0
  20. data/lib/hitimes/metric.rb +112 -0
  21. data/lib/hitimes/mutexed_stats.rb +28 -0
  22. data/lib/hitimes/paths.rb +53 -0
  23. data/lib/hitimes/stats.rb +54 -0
  24. data/lib/hitimes/timed_metric.rb +177 -0
  25. data/lib/hitimes/timed_value_metric.rb +235 -0
  26. data/lib/hitimes/value_metric.rb +72 -0
  27. data/lib/hitimes/version.rb +57 -0
  28. data/spec/interval_spec.rb +133 -0
  29. data/spec/metric_spec.rb +30 -0
  30. data/spec/mutex_stats_spec.rb +34 -0
  31. data/spec/paths_spec.rb +13 -0
  32. data/spec/spec_helper.rb +5 -0
  33. data/spec/stats_spec.rb +100 -0
  34. data/spec/timed_metric_spec.rb +155 -0
  35. data/spec/timed_value_metric_spec.rb +172 -0
  36. data/spec/value_metric_spec.rb +110 -0
  37. data/spec/version_spec.rb +33 -0
  38. data/tasks/announce.rake +42 -0
  39. data/tasks/config.rb +108 -0
  40. data/tasks/distribution.rake +77 -0
  41. data/tasks/documentation.rake +32 -0
  42. data/tasks/extension.rake +92 -0
  43. data/tasks/rspec.rake +31 -0
  44. data/tasks/rubyforge.rake +55 -0
  45. data/tasks/utils.rb +80 -0
  46. metadata +150 -0
@@ -0,0 +1,72 @@
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
+ @sampling_start_time ||= self.utc_microseconds()
46
+ @sampling_start_interval ||= Interval.now
47
+
48
+ @stats.update( value )
49
+
50
+ # update the length of time we have been sampling
51
+ @sampling_delta = @sampling_start_interval.duration_so_far
52
+ end
53
+
54
+ #
55
+ # :call-seq:
56
+ # metric.to_hash -> Hash
57
+ #
58
+ # Convert the metric to a hash
59
+ #
60
+ def to_hash
61
+ h = super
62
+ (Stats::STATS - %w[ rate ]).each do |s|
63
+ h[s] = self.send( s )
64
+ end
65
+ return h
66
+ end
67
+
68
+ # forward appropriate calls directly to the stats object
69
+ extend Forwardable
70
+ def_delegators :@stats, :count, :sum, :max, :mean, :min, :stddev, :sum, :sumsq
71
+ end
72
+ end
@@ -0,0 +1,57 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details
4
+ #++
5
+
6
+ module Hitimes
7
+ #
8
+ # module containing all the version information about Hitimes
9
+ #
10
+ module Version
11
+
12
+ # Major version number
13
+ MAJOR = 1
14
+
15
+ # Minor version number
16
+ MINOR = 0
17
+
18
+ # Build number
19
+ BUILD = 4
20
+
21
+ #
22
+ # :call-seq:
23
+ # Version.to_a -> [ MAJOR, MINOR, BUILD ]
24
+ #
25
+ # Return the version as an array of Integers
26
+ #
27
+ def self.to_a
28
+ [MAJOR, MINOR, BUILD]
29
+ end
30
+
31
+ #
32
+ # :call-seq:
33
+ # Version.to_s -> "MAJOR.MINOR.BUILD"
34
+ #
35
+ # Return the version as a String with dotted notation
36
+ #
37
+ def self.to_s
38
+ to_a.join(".")
39
+ end
40
+
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
50
+
51
+ # The Version in MAJOR.MINOR.BUILD dotted notation
52
+ STRING = Version.to_s
53
+ end
54
+
55
+ # The Version in MAJOR.MINOR.BUILD dotted notation
56
+ VERSION = Version.to_s
57
+ end
@@ -0,0 +1,133 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), "spec_helper.rb" ) )
2
+
3
+ require 'hitimes'
4
+
5
+ describe Hitimes::Interval do
6
+ it "has a 0 duration when newly created" do
7
+ i = Hitimes::Interval.new
8
+ i.duration == 0.0
9
+ end
10
+
11
+ it "knows if it has been started" do
12
+ i = Hitimes::Interval.new
13
+ i.should_not be_started
14
+
15
+ i.start
16
+ i.should be_started
17
+ end
18
+
19
+ it "knows if it has been stopped" do
20
+ i = Hitimes::Interval.new
21
+ i.start
22
+ i.should_not be_stopped
23
+ i.stop
24
+ i.should be_stopped
25
+ end
26
+
27
+ it "knows if it is currently running" do
28
+ i = Hitimes::Interval.new
29
+ i.should_not be_running
30
+ i.start
31
+ i.should be_running
32
+ i.stop
33
+ i.should_not be_running
34
+ end
35
+
36
+ it "can time a block of code" do
37
+ d = Hitimes::Interval.measure do
38
+ sleep 0.2
39
+ end
40
+ d.should be_close(0.2, 0.01)
41
+ end
42
+
43
+ it "raises an error if measure is called with no block" do
44
+ lambda{ Hitimes::Interval.measure }.should raise_error( Hitimes::Error )
45
+ end
46
+
47
+ it "creates an interval via #now" do
48
+ i = Hitimes::Interval.now
49
+ i.should be_started
50
+ i.should_not be_stopped
51
+ end
52
+
53
+ it "calling duration multiple times returns successivly grater durations" do
54
+ i = Hitimes::Interval.new
55
+ i.start
56
+ y = i.duration
57
+ z = i.duration
58
+ z.should > y
59
+ end
60
+
61
+ it "calling start multiple times on has no effect after the first call" do
62
+ i = Hitimes::Interval.new
63
+ i.start.should == true
64
+ x = i.start_instant
65
+ i.start_instant.should > 0
66
+ i.start.should == false
67
+ x.should == i.start_instant
68
+ end
69
+
70
+ it "returns the duration on the first call to stop" do
71
+ i = Hitimes::Interval.now
72
+ d = i.stop
73
+ d.should be_instance_of( Float )
74
+ end
75
+
76
+ it "calling stop multiple times on has no effect after the first call" do
77
+ i = Hitimes::Interval.new
78
+ i.start.should == true
79
+ i.stop
80
+
81
+ x = i.stop_instant
82
+ i.stop_instant.should > 0
83
+ i.stop.should == false
84
+ x.should == i.stop_instant
85
+
86
+ end
87
+
88
+ it "duration does not change after stop is calledd" do
89
+ i = Hitimes::Interval.new
90
+ i.start
91
+ x = i.stop
92
+ y = i.duration
93
+ i.stop.should == false
94
+
95
+ z = i.duration
96
+
97
+ x.should == y
98
+ x.should == z
99
+
100
+ y.should == z
101
+ end
102
+
103
+ it "can return how much time has elapsed from the start without stopping the interval" do
104
+ i = Hitimes::Interval.new
105
+ i.start
106
+ x = i.duration_so_far
107
+ i.should be_running
108
+ y = i.duration_so_far
109
+ i.stop
110
+ x.should < y
111
+ x.should < i.duration
112
+ y.should < i.duration
113
+ end
114
+
115
+ describe "#split" do
116
+
117
+ it "creates a new Interval object" do
118
+ i = Hitimes::Interval.new
119
+ i.start
120
+ i2 = i.split
121
+ i.object_id.should_not == i2.object_id
122
+ end
123
+
124
+ it "with the stop instant equivialent to the previous Interval's start instant" do
125
+ i = Hitimes::Interval.new
126
+ i.start
127
+ i2 = i.split
128
+ i.stop_instant.should == i2.start_instant
129
+ end
130
+ end
131
+
132
+ end
133
+
@@ -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
+
@@ -0,0 +1,34 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), "spec_helper.rb" ) )
2
+
3
+ require 'hitimes'
4
+ require 'hitimes/mutexed_stats'
5
+
6
+ describe Hitimes::MutexedStats do
7
+ before( :each ) do
8
+ @threads = 5
9
+ @iters = 10_000
10
+ @final_value = @threads * @iters
11
+ end
12
+
13
+ def run_with_scissors( stats, threads, iters )
14
+ spool = []
15
+ threads.times do |t|
16
+ spool << Thread.new { iters.times{ stats.update( 1 ) } }
17
+ end
18
+ spool.each { |t| t.join }
19
+ return stats
20
+ end
21
+
22
+ it "is unsafe normally" do
23
+ pending "not for MRI -- not interruptable in this C extension" do
24
+ stats = run_with_scissors( ::Hitimes::Stats.new, @threads, @iters )
25
+ stats.count.should_not == @final_value
26
+ end
27
+ end
28
+
29
+ it "has a threadsafe update" do
30
+ stats = run_with_scissors( ::Hitimes::MutexedStats.new, @threads, @iters )
31
+ stats.count.should == @final_value
32
+ end
33
+
34
+ end
@@ -0,0 +1,13 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), "spec_helper.rb" ) )
2
+
3
+ require 'hitimes/paths'
4
+
5
+ describe Hitimes::Paths do
6
+ it "can access the root dir of the project" do
7
+ Hitimes::Paths.root_dir.should == File.expand_path( File.join( File.dirname( __FILE__ ), ".." ) ) + ::File::SEPARATOR
8
+ end
9
+
10
+ it "can access the lib path of the project" do
11
+ Hitimes::Paths.lib_path.should == File.expand_path( File.join( File.dirname( __FILE__ ), "..", "lib" ) ) + ::File::SEPARATOR
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $: << File.expand_path(File.join(File.dirname(__FILE__),"..","lib"))
5
+
@@ -0,0 +1,100 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), "spec_helper.rb" ) )
2
+
3
+ require 'hitimes/stats'
4
+ require 'json'
5
+
6
+ describe Hitimes::Stats do
7
+ before( :each ) do
8
+ @stats = Hitimes::Stats.new
9
+ @full_stats = Hitimes::Stats.new
10
+
11
+ [ 1, 2, 3].each { |i| @full_stats.update( i ) }
12
+ end
13
+
14
+ it "is initialized with 0 values" do
15
+ @stats.count.should == 0
16
+ @stats.min.should == 0.0
17
+ @stats.max.should == 0.0
18
+ @stats.sum.should == 0.0
19
+ @stats.rate.should == 0.0
20
+ end
21
+
22
+ it "calculates the mean correctly" do
23
+ @full_stats.mean.should == 2.0
24
+ end
25
+
26
+ it "calculates the rate correctly" do
27
+ @full_stats.rate.should == 0.5
28
+ end
29
+
30
+ it "tracks the maximum value" do
31
+ @full_stats.max.should == 3.0
32
+ end
33
+
34
+ it "tracks the minimum value" do
35
+ @full_stats.min.should == 1.0
36
+ end
37
+
38
+ it "tracks the count" do
39
+ @full_stats.count.should == 3
40
+ end
41
+
42
+ it "tracks the sum" do
43
+ @full_stats.sum.should == 6.0
44
+ end
45
+
46
+ it "calculates the standard deviation" do
47
+ @full_stats.stddev.should == 1.0
48
+ end
49
+
50
+ it "calculates the sum of squares " do
51
+ @full_stats.sumsq.should == 14.0
52
+ end
53
+
54
+ describe "#to_hash " do
55
+ it "converts to a Hash" do
56
+ h = @full_stats.to_hash
57
+ h.size.should == ::Hitimes::Stats::STATS.size
58
+ h.keys.sort.should == ::Hitimes::Stats::STATS
59
+ end
60
+
61
+ it "converts to a limited Hash if given arguments" do
62
+ h = @full_stats.to_hash( "min", "max", "mean" )
63
+ h.size.should == 3
64
+ h.keys.sort.should == %w[ max mean min ]
65
+
66
+ h = @full_stats.to_hash( %w[ count rate ] )
67
+ h.size.should == 2
68
+ h.keys.sort.should == %w[ count rate ]
69
+ end
70
+
71
+ it "raises NoMethodError if an invalid stat is used" do
72
+ lambda { @full_stats.to_hash( "wibble" ) }.should raise_error( NoMethodError )
73
+ end
74
+ end
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
100
+ end