hitimes 1.1.0-java

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 (49) hide show
  1. data/HISTORY +69 -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/ext/java/src/hitimes/Hitimes.java +54 -0
  17. data/ext/java/src/hitimes/HitimesInterval.java +174 -0
  18. data/ext/java/src/hitimes/HitimesService.java +16 -0
  19. data/ext/java/src/hitimes/HitimesStats.java +112 -0
  20. data/gemspec.rb +65 -0
  21. data/lib/hitimes.rb +37 -0
  22. data/lib/hitimes/hitimes.jar +0 -0
  23. data/lib/hitimes/metric.rb +118 -0
  24. data/lib/hitimes/mutexed_stats.rb +32 -0
  25. data/lib/hitimes/paths.rb +53 -0
  26. data/lib/hitimes/stats.rb +58 -0
  27. data/lib/hitimes/timed_metric.rb +176 -0
  28. data/lib/hitimes/timed_value_metric.rb +233 -0
  29. data/lib/hitimes/value_metric.rb +71 -0
  30. data/lib/hitimes/version.rb +57 -0
  31. data/spec/interval_spec.rb +133 -0
  32. data/spec/metric_spec.rb +30 -0
  33. data/spec/mutex_stats_spec.rb +34 -0
  34. data/spec/paths_spec.rb +13 -0
  35. data/spec/spec_helper.rb +5 -0
  36. data/spec/stats_spec.rb +100 -0
  37. data/spec/timed_metric_spec.rb +155 -0
  38. data/spec/timed_value_metric_spec.rb +172 -0
  39. data/spec/value_metric_spec.rb +110 -0
  40. data/spec/version_spec.rb +33 -0
  41. data/tasks/announce.rake +42 -0
  42. data/tasks/config.rb +109 -0
  43. data/tasks/distribution.rake +93 -0
  44. data/tasks/documentation.rake +32 -0
  45. data/tasks/extension.rake +108 -0
  46. data/tasks/rspec.rake +33 -0
  47. data/tasks/rubyforge.rake +55 -0
  48. data/tasks/utils.rb +80 -0
  49. metadata +191 -0
@@ -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 = 1
17
+
18
+ # Build number
19
+ BUILD = 0
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.02)
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
@@ -0,0 +1,155 @@
1
+ require File.expand_path( File.join( File.dirname( __FILE__ ), "spec_helper.rb" ) )
2
+
3
+ require 'hitimes/timed_metric'
4
+
5
+ describe Hitimes::TimedMetric do
6
+ before( :each ) do
7
+ @tm = Hitimes::TimedMetric.new( 'test-timed-metric' )
8
+ end
9
+
10
+ it "knows if it is running or not" do
11
+ @tm.should_not be_running
12
+ @tm.start
13
+ @tm.should be_running
14
+ @tm.stop
15
+ @tm.should_not be_running
16
+ end
17
+
18
+ it "#split returns the last duration and the timer is still running" do
19
+ @tm.start
20
+ d = @tm.split
21
+ @tm.should be_running
22
+ d.should > 0
23
+ @tm.count.should == 1
24
+ @tm.duration.should == d
25
+ end
26
+
27
+ it "#stop returns false if called more than once in a row" do
28
+ @tm.start
29
+ @tm.stop.should > 0
30
+ @tm.stop.should == false
31
+ end
32
+
33
+ it "does not count a currently running interval as an interval in calculations" do
34
+ @tm.start
35
+ @tm.count.should == 0
36
+ @tm.split
37
+ @tm.count.should == 1
38
+ end
39
+
40
+ it "#split called on a stopped timer does nothing" do
41
+ @tm.start
42
+ @tm.stop
43
+ @tm.split.should == false
44
+ end
45
+
46
+ it "calculates the mean of the durations" do
47
+ 2.times { @tm.start ; sleep 0.05 ; @tm.stop }
48
+ @tm.mean.should be_close( 0.05, 0.01 )
49
+ end
50
+
51
+ it "calculates the rate of the counts " do
52
+ 5.times { @tm.start ; sleep 0.05 ; @tm.stop }
53
+ @tm.rate.should be_close( 20.00, 0.1 )
54
+ end
55
+
56
+
57
+ it "calculates the stddev of the durations" do
58
+ 3.times { |x| @tm.start ; sleep (0.05 * x) ; @tm.stop }
59
+ @tm.stddev.should be_close( 0.05, 0.001)
60
+ end
61
+
62
+ it "returns 0.0 for stddev if there is no data" do
63
+ @tm.stddev.should == 0.0
64
+ end
65
+
66
+ it "keeps track of the min value" do
67
+ 2.times { @tm.start ; sleep 0.05 ; @tm.stop }
68
+ @tm.min.should be_close( 0.05, 0.002 )
69
+ end
70
+
71
+ it "keeps track of the max value" do
72
+ 2.times { @tm.start ; sleep 0.05 ; @tm.stop }
73
+ @tm.max.should be_close( 0.05, 0.002 )
74
+ end
75
+
76
+ it "keeps track of the sum value" do
77
+ 2.times { @tm.start ; sleep 0.05 ; @tm.stop }
78
+ @tm.sum.should be_close( 0.10, 0.002 )
79
+ end
80
+
81
+ it "keeps track of the sum of squars value" do
82
+ 3.times { @tm.start ; sleep 0.05 ; @tm.stop }
83
+ @tm.sumsq.should be_close( 0.0075, 0.0001 )
84
+ end
85
+
86
+ it "keeps track of the minimum start time of all the intervals" do
87
+ f1 = Time.now.gmtime.to_f * 1_000_000
88
+ 5.times { @tm.start ; sleep 0.05 ; @tm.stop }
89
+ f2 = Time.now.gmtime.to_f * 1_000_000
90
+ @tm.sampling_start_time.should >= f1
91
+ @tm.sampling_start_time.should < f2
92
+ # distance from now to start time should be greater than the distance from
93
+ # the start to the min start_time
94
+ (f2 - @tm.sampling_start_time).should > ( @tm.sampling_start_time - f1 )
95
+ end
96
+
97
+ it "keeps track of the last stop time of all the intervals" do
98
+ f1 = Time.now.gmtime.to_f * 1_000_000
99
+ 5.times { @tm.start ; sleep 0.05 ; @tm.stop }
100
+ f2 = Time.now.gmtime.to_f * 1_000_000
101
+ @tm.sampling_stop_time.should > f1
102
+ @tm.sampling_stop_time.should <= f2
103
+ # distance from now to max stop time time should be less than the distance
104
+ # from the start to the max stop time
105
+ (f2 - @tm.sampling_stop_time).should < ( @tm.sampling_stop_time - f1 )
106
+ end
107
+
108
+ it "can create an already running timer" do
109
+ t = Hitimes::TimedMetric.now( 'already-running' )
110
+ t.should be_running
111
+ end
112
+
113
+ it "can measure a block of code from an instance" do
114
+ t = Hitimes::TimedMetric.new( 'measure a block' )
115
+ 3.times { t.measure { sleep 0.05 } }
116
+ t.duration.should be_close( 0.15, 0.001 )
117
+ t.count.should == 3
118
+ end
119
+
120
+ it "returns the value of the block when measuring" do
121
+ t = Hitimes::TimedMetric.new( 'measure a block' )
122
+ x = t.measure { sleep 0.05; 42 }
123
+ t.duration.should be_close( 0.05, 0.001 )
124
+ x.should == 42
125
+ end
126
+
127
+ describe "#to_hash" do
128
+
129
+ it "has name value" do
130
+ h = @tm.to_hash
131
+ h['name'].should == "test-timed-metric"
132
+ end
133
+
134
+ it "has an empty hash for additional_data" do
135
+ h = @tm.to_hash
136
+ h['additional_data'].should == Hash.new
137
+ h['additional_data'].size.should == 0
138
+ end
139
+
140
+ it "has the right sum" do
141
+ 10.times { |x| @tm.measure { sleep 0.01*x } }
142
+ h = @tm.to_hash
143
+ h['sum'].should be_close( 0.45, 0.003 )
144
+ end
145
+
146
+ fields = ::Hitimes::Stats::STATS.dup + %w[ name additional_data sampling_start_time sampling_stop_time ]
147
+ fields.each do |f|
148
+ it "should have a value for #{f}" do
149
+ @tm.measure { sleep 0.001 }
150
+ h = @tm.to_hash
151
+ h[f].should_not be_nil
152
+ end
153
+ end
154
+ end
155
+ end