hitimes 1.0.4-x86-mingw32

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,269 @@
1
+ /**
2
+ * Copyright (c) 2008 Jeremy Hinegardner
3
+ * All rights reserved. See LICENSE and/or COPYING for details.
4
+ *
5
+ * vim: shiftwidth=4
6
+ */
7
+
8
+ #include "hitimes_stats.h"
9
+
10
+ /* classes defined here */
11
+ VALUE cH_Stats; /* Hitimes::Stats */
12
+
13
+ /**
14
+ * Allocator and Deallocator for Stats classes
15
+ */
16
+
17
+ VALUE hitimes_stats_free(hitimes_stats_t* s)
18
+ {
19
+ xfree( s );
20
+ return Qnil;
21
+ }
22
+
23
+ VALUE hitimes_stats_alloc(VALUE klass)
24
+ {
25
+ VALUE obj;
26
+ hitimes_stats_t* s = xmalloc( sizeof( hitimes_stats_t ) );
27
+
28
+ s->min = 0.0;
29
+ s->max = 0.0;
30
+ s->count = 0;
31
+ s->sum = 0.0;
32
+ s->sumsq = 0.0;
33
+
34
+ obj = Data_Wrap_Struct(klass, NULL, hitimes_stats_free, s);
35
+
36
+ return obj;
37
+ }
38
+
39
+
40
+ /**
41
+ * call-seq:
42
+ * stat.update( val ) -> val
43
+ *
44
+ * Update the running stats with the new value.
45
+ * Return the input value.
46
+ */
47
+ VALUE hitimes_stats_update( VALUE self, VALUE v )
48
+ {
49
+ long double new_v;
50
+ hitimes_stats_t *stats;
51
+
52
+ Data_Get_Struct( self, hitimes_stats_t, stats );
53
+ new_v = NUM2DBL( v );
54
+
55
+ if ( 0 == stats->count ) {
56
+ stats->min = new_v;
57
+ stats->max = new_v;
58
+ } else {
59
+ stats->min = ( new_v < stats->min) ? ( new_v ) : ( stats->min );
60
+ stats->max = ( new_v > stats->max) ? ( new_v ) : ( stats->max );
61
+ }
62
+
63
+ stats->count += 1;
64
+ stats->sum += new_v;
65
+ stats->sumsq += ( new_v * new_v );
66
+
67
+ return v;
68
+ }
69
+
70
+ /**
71
+ * call-seq:
72
+ * stat.mean -> Float
73
+ *
74
+ * Return the arithmetic mean of the values put into the Stats object. If no
75
+ * values have passed through the stats object then 0.0 is returned;
76
+ */
77
+ VALUE hitimes_stats_mean( VALUE self )
78
+ {
79
+ hitimes_stats_t *stats;
80
+ long double mean = 0.0;
81
+
82
+ Data_Get_Struct( self, hitimes_stats_t, stats );
83
+
84
+ if ( stats->count > 0 ) {
85
+ mean = stats->sum / stats->count ;
86
+ }
87
+
88
+ return rb_float_new( mean );
89
+ }
90
+
91
+
92
+ /**
93
+ * call-seq:
94
+ * stat.rate -> Float
95
+ *
96
+ * Return the +count+ divided by +sum+.
97
+ *
98
+ * In many cases when Stats#update( _value_ ) is called, the _value_ is a unit
99
+ * of time, typically seconds or microseconds. #rate is a convenience for those
100
+ * times. In this case, where _value_ is a unit if time, then count divided by
101
+ * sum is a useful value, i.e. +something per unit of time+.
102
+ *
103
+ * In the case where _value_ is a non-time related value, then the value
104
+ * returned by _rate_ is not really useful.
105
+ *
106
+ */
107
+ VALUE hitimes_stats_rate( VALUE self )
108
+ {
109
+ hitimes_stats_t *stats;
110
+ long double rate = 0.0;
111
+
112
+ Data_Get_Struct( self, hitimes_stats_t, stats );
113
+
114
+ if ( stats->sum > 0.0 ) {
115
+ rate = stats->count / stats->sum;
116
+ }
117
+
118
+ return rb_float_new( rate );
119
+ }
120
+
121
+
122
+ /**
123
+ * call-seq:
124
+ * stat.max -> Float
125
+ *
126
+ * Return the maximum value that has passed through the Stats object
127
+ */
128
+ VALUE hitimes_stats_max( VALUE self )
129
+ {
130
+ hitimes_stats_t *stats;
131
+
132
+ Data_Get_Struct( self, hitimes_stats_t, stats );
133
+
134
+ return rb_float_new( stats->max );
135
+ }
136
+
137
+
138
+
139
+ /**
140
+ * call-seq:
141
+ * stat.min -> Float
142
+ *
143
+ * Return the minimum value that has passed through the Stats object
144
+ */
145
+ VALUE hitimes_stats_min( VALUE self )
146
+ {
147
+ hitimes_stats_t *stats;
148
+
149
+ Data_Get_Struct( self, hitimes_stats_t, stats );
150
+
151
+ return rb_float_new( stats->min );
152
+ }
153
+
154
+
155
+ /**
156
+ * call-seq:
157
+ * stat.count -> Integer
158
+ *
159
+ * Return the number of values that have passed through the Stats object.
160
+ */
161
+ VALUE hitimes_stats_count( VALUE self )
162
+ {
163
+ hitimes_stats_t *stats;
164
+
165
+ Data_Get_Struct( self, hitimes_stats_t, stats );
166
+
167
+ return LONG2NUM( stats->count );
168
+ }
169
+
170
+
171
+ /**
172
+ * call-seq:
173
+ * stat.sum -> Float
174
+ *
175
+ * Return the sum of all the values that have passed through the Stats object.
176
+ */
177
+ VALUE hitimes_stats_sum( VALUE self )
178
+ {
179
+ hitimes_stats_t *stats;
180
+
181
+ Data_Get_Struct( self, hitimes_stats_t, stats );
182
+
183
+ return rb_float_new( stats->sum );
184
+ }
185
+
186
+ /**
187
+ * call-seq:
188
+ * stat.sumsq -> Float
189
+ *
190
+ * Return the sum of the squars of all the values that passed through the Stats
191
+ * object.
192
+ */
193
+ VALUE hitimes_stats_sumsq( VALUE self )
194
+ {
195
+ hitimes_stats_t *stats;
196
+
197
+ Data_Get_Struct( self, hitimes_stats_t, stats );
198
+
199
+ return rb_float_new( stats->sumsq );
200
+ }
201
+
202
+
203
+ /**
204
+ * call-seq:
205
+ * stat.stddev -> Float
206
+ *
207
+ * Return the standard deviation of all the values that have passed through the
208
+ * Stats object. The standard deviation has no meaning unless the count is > 1,
209
+ * therefore if the current _stat.count_ is < 1 then 0.0 will be returned;
210
+ */
211
+ VALUE hitimes_stats_stddev ( VALUE self )
212
+ {
213
+ hitimes_stats_t *stats;
214
+ long double stddev = 0.0;
215
+
216
+ Data_Get_Struct( self, hitimes_stats_t, stats );
217
+ if ( stats->count > 1 ) {
218
+ stddev = sqrt( ( stats->sumsq - ( stats->sum * stats->sum / stats->count ) ) / ( stats->count - 1 ) );
219
+ }
220
+
221
+ return rb_float_new( stddev );
222
+ }
223
+
224
+
225
+ /**
226
+ * Document-class: Hitimes::Stats
227
+ *
228
+ * The Stats class encapulsates capturing and reporting statistics. It is
229
+ * modeled after the RFuzz::Sampler class, but implemented in C. For general use
230
+ * you allocate a new Stats object, and then update it with new values. The
231
+ * Stats object will keep track of the _min_, _max_, _count_, _sum_ and _sumsq_
232
+ * and when you want you may also retrieve the _mean_, _stddev_ and _rate_.
233
+ *
234
+ * this contrived example shows getting a list of all the files in a directory
235
+ * and running stats on file sizes.
236
+ *
237
+ * s = Hitimes::Stats.new
238
+ * dir = ARGV.shift || Dir.pwd
239
+ * Dir.entries( dir ).each do |entry|
240
+ * fs = File.stat( entry )
241
+ * if fs.file? then
242
+ * s.update( fs.size )
243
+ * end
244
+ * end
245
+ *
246
+ * %w[ count min max mean sum stddev rate ].each do |m|
247
+ * puts "#{m.rjust(6)} : #{s.send( m ) }"
248
+ * end
249
+ */
250
+ void Init_hitimes_stats()
251
+ {
252
+
253
+ mH = rb_define_module("Hitimes");
254
+
255
+ cH_Stats = rb_define_class_under( mH, "Stats", rb_cObject ); /* in hitimes_stats.c */
256
+ rb_define_alloc_func( cH_Stats, hitimes_stats_alloc );
257
+
258
+ rb_define_method( cH_Stats, "update", hitimes_stats_update, 1 ); /* in hitimes_stats.c */
259
+
260
+ rb_define_method( cH_Stats, "count", hitimes_stats_count, 0 ); /* in hitimes_stats.c */
261
+ rb_define_method( cH_Stats, "max", hitimes_stats_max, 0 ); /* in hitimes_stats.c */
262
+ rb_define_method( cH_Stats, "mean", hitimes_stats_mean, 0 ); /* in hitimes_stats.c */
263
+ rb_define_method( cH_Stats, "min", hitimes_stats_min, 0 ); /* in hitimes_stats.c */
264
+ rb_define_method( cH_Stats, "rate", hitimes_stats_rate, 0 ); /* in hitimes_stats.c */
265
+ rb_define_method( cH_Stats, "sum", hitimes_stats_sum, 0 ); /* in hitimes_stats.c */
266
+ rb_define_method( cH_Stats, "sumsq", hitimes_stats_sumsq, 0 ); /* in hitimes_stats.c */
267
+ rb_define_method( cH_Stats, "stddev", hitimes_stats_stddev, 0 ); /* in hitimes_stats.c */
268
+ }
269
+
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Copyright (c) 2008 Jeremy Hinegardner
3
+ * All rights reserved. See LICENSE and/or COPYING for details.
4
+ *
5
+ * vim: shiftwidth=4
6
+ */
7
+
8
+ #ifndef __HITIMES_STATS_H__
9
+ #define __HITIMES_STATS_H__
10
+
11
+ #include <ruby.h>
12
+ #include <math.h>
13
+
14
+ /* classes and modules defined elswhere */
15
+ extern VALUE mH; /* Hitimes */
16
+ extern VALUE eH_Error; /* Hitimes::Error */
17
+ extern VALUE cH_Stats; /* Hitimes::Stats */
18
+
19
+
20
+ typedef struct hitimes_stats {
21
+ long double min;
22
+ long double max;
23
+ long double sum;
24
+ long double sumsq;
25
+ long long count;
26
+ } hitimes_stats_t;
27
+
28
+ #endif
29
+
30
+
data/gemspec.rb ADDED
@@ -0,0 +1,60 @@
1
+ require 'rubygems'
2
+ require 'hitimes/version'
3
+ require 'tasks/config'
4
+
5
+ Hitimes::GEM_SPEC = Gem::Specification.new do |spec|
6
+ proj = Configuration.for('project')
7
+ spec.name = proj.name
8
+ spec.version = Hitimes::VERSION
9
+
10
+ spec.author = proj.author
11
+ spec.email = proj.email
12
+ spec.homepage = proj.homepage
13
+ spec.summary = proj.summary
14
+ spec.description = proj.description
15
+ spec.platform = Gem::Platform::RUBY
16
+
17
+
18
+ pkg = Configuration.for('packaging')
19
+ spec.files = pkg.files.all
20
+ spec.executables = pkg.files.bin.collect { |b| File.basename(b) }
21
+
22
+ # add dependencies here
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")
27
+ spec.add_development_dependency( "rake-compiler", "~> 0.5.0")
28
+
29
+ if ext_conf = Configuration.for_if_exist?("extension") then
30
+ spec.extensions << ext_conf.configs
31
+ spec.require_paths << 'ext'
32
+ spec.extensions.flatten!
33
+ end
34
+
35
+ if rdoc = Configuration.for_if_exist?('rdoc') then
36
+ spec.has_rdoc = true
37
+ spec.extra_rdoc_files = pkg.files.rdoc
38
+ spec.rdoc_options = rdoc.options + [ "--main" , rdoc.main_page ]
39
+ else
40
+ spec.has_rdoc = false
41
+ end
42
+
43
+ if test = Configuration.for_if_exist?('testing') then
44
+ spec.test_files = test.files
45
+ end
46
+
47
+ if rf = Configuration.for_if_exist?('rubyforge') then
48
+ spec.rubyforge_project = rf.project
49
+ end
50
+ end
51
+
52
+ Hitimes::GEM_SPEC_MSWIN32 = Hitimes::GEM_SPEC.clone
53
+ Hitimes::GEM_SPEC_MSWIN32.platform = ::Gem::Platform.new( "i386-mswin32" )
54
+ Hitimes::GEM_SPEC_MSWIN32.extensions = []
55
+
56
+ Hitimes::GEM_SPEC_MINGW32= Hitimes::GEM_SPEC.clone
57
+ Hitimes::GEM_SPEC_MINGW32.platform = ::Gem::Platform.new( "i386-mingw32" )
58
+ Hitimes::GEM_SPEC_MINGW32.extensions = []
59
+
60
+ Hitimes::SPECS = [ Hitimes::GEM_SPEC, Hitimes::GEM_SPEC_MSWIN32, Hitimes::GEM_SPEC_MINGW32 ]
data/lib/hitimes.rb ADDED
@@ -0,0 +1,31 @@
1
+ #--
2
+ # Copyright (c) 2008 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ #
7
+ # The top level module containing the contents of the hitimes library
8
+ #
9
+ # use the library with:
10
+ #
11
+ # require 'hitimes'
12
+ #
13
+ module Hitimes
14
+ #
15
+ # Base class of all errors in Hitimes
16
+ #
17
+ class Error < ::StandardError; end
18
+ end
19
+ require 'hitimes/paths'
20
+ require 'hitimes/version'
21
+
22
+ # use a version subdirectory for extensions, initially to support windows, but
23
+ # why make a special case. It doesn't hurt anyone to have an extra subdir.
24
+ require "hitimes/#{RUBY_VERSION.sub(/\.\d$/,'')}/hitimes_ext"
25
+ require 'hitimes/stats'
26
+ require 'hitimes/mutexed_stats'
27
+ require 'hitimes/metric'
28
+ require 'hitimes/value_metric'
29
+ require 'hitimes/timed_metric'
30
+ require 'hitimes/timed_value_metric'
31
+
Binary file
Binary file
@@ -0,0 +1,112 @@
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 number of seconds as a float since the sampling_start_time
20
+ attr_reader :sampling_delta
21
+
22
+ # An additional hash of data to associate with the metric
23
+ attr_reader :additional_data
24
+
25
+ # The 'name' to associate with the metric
26
+ attr_reader :name
27
+
28
+ #
29
+ # :call-seq:
30
+ # Metric.new( 'my_metric' ) -> Metric
31
+ # Metric.new( 'my_metric', 'foo' => 'bar', 'this' => 42 ) -> Metric
32
+ #
33
+ # Create a new ValueMetric giving it a name and additional data.
34
+ #
35
+ # +additional_data+ may be anything that follows the +to_hash+ protocol.
36
+ # +name+ may be anything that follows the +to_s+ protocol.
37
+ #
38
+ def initialize( name, additional_data = {} )
39
+ @sampling_start_time = nil
40
+ @sampling_start_interval = nil
41
+ @sampling_delta = 0
42
+
43
+ @name = name.to_s
44
+ @additional_data = additional_data.to_hash
45
+ end
46
+
47
+ #
48
+ # :call-seq:
49
+ # metric.sampling_start_time -> Float or nil
50
+ #
51
+ # The time at which the first sample was taken.
52
+ # This is the number of microseconds since UNIX epoch UTC as a Float
53
+ #
54
+ # If the metric has not started measuring then the start time is nil.
55
+ #
56
+ def sampling_start_time
57
+ if @sampling_start_interval then
58
+ @sampling_start_time ||= self.utc_microseconds()
59
+ else
60
+ nil
61
+ end
62
+ end
63
+
64
+ #
65
+ # :call-seq:
66
+ # metric.sampling_stop_time -> Float or nil
67
+ #
68
+ # The time at which the last sample was taken
69
+ # This is the number of microseconds since UNIX epoch UTC as a Float
70
+ #
71
+ # If the metric has not completely measured at least one thing then
72
+ # stop time is nil.
73
+ #
74
+ # Because accessing the actual 'time of day' is an expesive operation, we
75
+ # only get the time of day at the beginning of the first measurement and we
76
+ # keep track of the offset from that point in @sampling_delta.
77
+ #
78
+ # When sampling_stop_time is called, the actual time of day is caculated.
79
+ #
80
+ def sampling_stop_time
81
+ if @sampling_delta > 0 then
82
+ (self.sampling_start_time + (@sampling_delta * 1_000_000))
83
+ else
84
+ nil
85
+ end
86
+ end
87
+
88
+ #
89
+ # :call-seq:
90
+ # metric.to_hash -> Hash
91
+ # metric.to_hash
92
+ #
93
+ # Convert the metric to a Hash.
94
+ #
95
+ def to_hash
96
+ { 'sampling_start_time' => self.sampling_start_time,
97
+ 'sampling_stop_time' => self.sampling_stop_time,
98
+ 'additional_data' => self.additional_data,
99
+ 'name' => self.name }
100
+ end
101
+
102
+ #
103
+ # :call-seq:
104
+ # metric.utc_microseconds -> Float
105
+ #
106
+ # The current time in microseconds from the UNIX Epoch in the UTC
107
+ #
108
+ def utc_microseconds
109
+ Time.now.gmtime.to_f * 1_000_000
110
+ end
111
+ end
112
+ end