hitimes 1.1.0-java

Sign up to get free protection for your applications and to get access to all the features.
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