hitimes 1.0.4-x86-mswin32

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