hitimes 1.3.0-x64-mingw32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CONTRIBUTING.md +57 -0
- data/HISTORY.md +124 -0
- data/LICENSE +16 -0
- data/Manifest.txt +44 -0
- data/README.md +200 -0
- data/Rakefile +28 -0
- data/examples/benchmarks.rb +113 -0
- data/examples/stats.rb +31 -0
- data/ext/hitimes/c/extconf.rb +24 -0
- data/ext/hitimes/c/hitimes.c +37 -0
- data/ext/hitimes/c/hitimes_instant_clock_gettime.c +28 -0
- data/ext/hitimes/c/hitimes_instant_osx.c +45 -0
- data/ext/hitimes/c/hitimes_instant_windows.c +27 -0
- data/ext/hitimes/c/hitimes_interval.c +370 -0
- data/ext/hitimes/c/hitimes_interval.h +73 -0
- data/ext/hitimes/c/hitimes_stats.c +269 -0
- data/ext/hitimes/c/hitimes_stats.h +30 -0
- data/ext/hitimes/java/src/hitimes/Hitimes.java +66 -0
- data/ext/hitimes/java/src/hitimes/HitimesInterval.java +176 -0
- data/ext/hitimes/java/src/hitimes/HitimesService.java +16 -0
- data/ext/hitimes/java/src/hitimes/HitimesStats.java +112 -0
- data/lib/hitimes.rb +66 -0
- data/lib/hitimes/2.0/hitimes.so +0 -0
- data/lib/hitimes/2.1/hitimes.so +0 -0
- data/lib/hitimes/2.2/hitimes.so +0 -0
- data/lib/hitimes/2.3/hitimes.so +0 -0
- data/lib/hitimes/2.4/hitimes.so +0 -0
- data/lib/hitimes/2.5/hitimes.so +0 -0
- data/lib/hitimes/metric.rb +118 -0
- data/lib/hitimes/mutexed_stats.rb +32 -0
- data/lib/hitimes/paths.rb +53 -0
- data/lib/hitimes/stats.rb +58 -0
- data/lib/hitimes/timed_metric.rb +176 -0
- data/lib/hitimes/timed_value_metric.rb +233 -0
- data/lib/hitimes/value_metric.rb +71 -0
- data/lib/hitimes/version.rb +8 -0
- data/spec/hitimes_spec.rb +24 -0
- data/spec/interval_spec.rb +136 -0
- data/spec/metric_spec.rb +28 -0
- data/spec/mutex_stats_spec.rb +36 -0
- data/spec/paths_spec.rb +11 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/stats_spec.rb +98 -0
- data/spec/timed_metric_spec.rb +155 -0
- data/spec/timed_value_metric_spec.rb +171 -0
- data/spec/value_metric_spec.rb +108 -0
- data/spec/version_spec.rb +7 -0
- data/tasks/default.rake +242 -0
- data/tasks/extension.rake +38 -0
- data/tasks/this.rb +208 -0
- metadata +216 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
package hitimes;
|
2
|
+
|
3
|
+
import java.io.IOException;
|
4
|
+
|
5
|
+
import org.jruby.Ruby;
|
6
|
+
|
7
|
+
import org.jruby.runtime.load.BasicLibraryService;
|
8
|
+
|
9
|
+
public class HitimesService implements BasicLibraryService {
|
10
|
+
public boolean basicLoad( final Ruby runtime ) throws IOException {
|
11
|
+
Hitimes.createHitimesModule( runtime );
|
12
|
+
return true;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
|
16
|
+
|
@@ -0,0 +1,112 @@
|
|
1
|
+
package hitimes;
|
2
|
+
|
3
|
+
import org.jruby.Ruby;
|
4
|
+
import org.jruby.RubyClass;
|
5
|
+
import org.jruby.RubyObject;
|
6
|
+
|
7
|
+
import org.jruby.RubyNumeric;
|
8
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
9
|
+
import org.jruby.runtime.ObjectAllocator;
|
10
|
+
|
11
|
+
import org.jruby.anno.JRubyMethod;
|
12
|
+
import org.jruby.anno.JRubyClass;
|
13
|
+
|
14
|
+
@JRubyClass( name = "Hitimes::Stats" )
|
15
|
+
public class HitimesStats extends RubyObject {
|
16
|
+
|
17
|
+
private double min = 0.0;
|
18
|
+
private double max = 0.0;
|
19
|
+
private double sum = 0.0;
|
20
|
+
private double sumsq = 0.0;
|
21
|
+
private long count = 0;
|
22
|
+
|
23
|
+
public static final ObjectAllocator ALLOCATOR = new ObjectAllocator() {
|
24
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klass) {
|
25
|
+
return new HitimesStats( runtime, klass );
|
26
|
+
}
|
27
|
+
};
|
28
|
+
|
29
|
+
public HitimesStats( Ruby runtime, RubyClass klass ) {
|
30
|
+
super( runtime, klass );
|
31
|
+
}
|
32
|
+
|
33
|
+
@JRubyMethod( name = "update", required = 1, argTypes = RubyNumeric.class )
|
34
|
+
public IRubyObject update( IRubyObject val ) {
|
35
|
+
double v = RubyNumeric.num2dbl( val );
|
36
|
+
|
37
|
+
if ( 0 == this.count ) {
|
38
|
+
this.min = this.max = v;
|
39
|
+
} else {
|
40
|
+
this.min = ( v < this.min ) ? v : this.min;
|
41
|
+
this.max = ( v > this.max ) ? v : this.max;
|
42
|
+
}
|
43
|
+
|
44
|
+
this.count += 1;
|
45
|
+
this.sum += v;
|
46
|
+
this.sumsq += (v * v);
|
47
|
+
|
48
|
+
return val;
|
49
|
+
}
|
50
|
+
|
51
|
+
@JRubyMethod( name = "mean" )
|
52
|
+
public IRubyObject mean() {
|
53
|
+
double mean = 0.0;
|
54
|
+
|
55
|
+
if ( this.count > 0 ) {
|
56
|
+
mean = this.sum / this.count;
|
57
|
+
}
|
58
|
+
|
59
|
+
return getRuntime().newFloat( mean );
|
60
|
+
}
|
61
|
+
|
62
|
+
|
63
|
+
@JRubyMethod( name = "rate" )
|
64
|
+
public IRubyObject rate() {
|
65
|
+
double rate = 0.0;
|
66
|
+
|
67
|
+
if ( this.sum > 0.0 ) {
|
68
|
+
rate = this.count / this.sum ;
|
69
|
+
}
|
70
|
+
|
71
|
+
return getRuntime().newFloat( rate );
|
72
|
+
}
|
73
|
+
|
74
|
+
@JRubyMethod( name = "stddev" )
|
75
|
+
public IRubyObject stddev() {
|
76
|
+
double stddev = 0.0;
|
77
|
+
|
78
|
+
if ( this.count > 1 ) {
|
79
|
+
double sq_sum = this.sum * this.sum;
|
80
|
+
stddev = Math.sqrt( ( this.sumsq - ( sq_sum / this.count ) ) / ( this.count - 1 ) );
|
81
|
+
}
|
82
|
+
return getRuntime().newFloat( stddev );
|
83
|
+
}
|
84
|
+
|
85
|
+
|
86
|
+
@JRubyMethod( name = "min" )
|
87
|
+
public IRubyObject min() {
|
88
|
+
return getRuntime().newFloat( this.min );
|
89
|
+
}
|
90
|
+
|
91
|
+
@JRubyMethod( name = "max" )
|
92
|
+
public IRubyObject max() {
|
93
|
+
return getRuntime().newFloat( this.max );
|
94
|
+
}
|
95
|
+
|
96
|
+
@JRubyMethod( name = "sum" )
|
97
|
+
public IRubyObject sum() {
|
98
|
+
return getRuntime().newFloat( this.sum );
|
99
|
+
}
|
100
|
+
|
101
|
+
@JRubyMethod( name = "sumsq" )
|
102
|
+
public IRubyObject sumsq() {
|
103
|
+
return getRuntime().newFloat( this.sumsq );
|
104
|
+
}
|
105
|
+
|
106
|
+
@JRubyMethod( name = "count" )
|
107
|
+
public IRubyObject count() {
|
108
|
+
return getRuntime().newFixnum( this.count );
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
|
data/lib/hitimes.rb
ADDED
@@ -0,0 +1,66 @@
|
|
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
|
+
|
19
|
+
# Hitimes.measure { } -> Float
|
20
|
+
#
|
21
|
+
# Times the execution of the block, returning the number of seconds it took
|
22
|
+
def self.measure(&block)
|
23
|
+
Hitimes::Interval.measure(&block)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
require 'hitimes/paths'
|
27
|
+
require 'hitimes/version'
|
28
|
+
|
29
|
+
# Load the binary extension, try loading one for the specific version of ruby
|
30
|
+
# and if that fails, then fall back to one in the top of the library.
|
31
|
+
# this is the method recommended by rake-compiler
|
32
|
+
|
33
|
+
attempts = [
|
34
|
+
"hitimes/#{RUBY_VERSION.sub(/\.\d+$/,'')}/hitimes",
|
35
|
+
"hitimes/hitimes"
|
36
|
+
]
|
37
|
+
loaded = false
|
38
|
+
|
39
|
+
path_exceptions = []
|
40
|
+
attempts.each do |path|
|
41
|
+
begin
|
42
|
+
require path
|
43
|
+
loaded = true
|
44
|
+
break
|
45
|
+
rescue LoadError => load_error
|
46
|
+
full_path = File.expand_path(path)
|
47
|
+
path_exceptions << [ full_path, load_error.message ]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if !loaded then
|
52
|
+
msg = ["Unable to find binary extension, was hitimes installed correctly? The following paths were tried."]
|
53
|
+
path_exceptions.each do |path, message|
|
54
|
+
msg << "#{path} : #{message}"
|
55
|
+
end
|
56
|
+
raise LoadError, msg.join("\n")
|
57
|
+
end
|
58
|
+
|
59
|
+
require 'hitimes/stats'
|
60
|
+
require 'hitimes/mutexed_stats'
|
61
|
+
|
62
|
+
require 'hitimes/metric'
|
63
|
+
require 'hitimes/value_metric'
|
64
|
+
require 'hitimes/timed_metric'
|
65
|
+
require 'hitimes/timed_value_metric'
|
66
|
+
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,118 @@
|
|
1
|
+
|
2
|
+
#--
|
3
|
+
# Copyright (c) 2008, 2009 Jeremy Hinegardner
|
4
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
5
|
+
#++
|
6
|
+
|
7
|
+
module Hitimes
|
8
|
+
#
|
9
|
+
# Metric hold the common meta information for all derived metric classes
|
10
|
+
#
|
11
|
+
# All metrics hold the meta information of:
|
12
|
+
#
|
13
|
+
# * The name of the metric
|
14
|
+
# * The time of day the first measurement is taken
|
15
|
+
# * The time of day the last measurement is taken
|
16
|
+
# * additional data
|
17
|
+
#
|
18
|
+
# Each derived class is assumed to set the sampling_start_time and
|
19
|
+
# sampling_stop_time appropriately.
|
20
|
+
#
|
21
|
+
# Metric itself should generally not be used. Only use the derived classes.
|
22
|
+
#
|
23
|
+
class Metric
|
24
|
+
|
25
|
+
# the number of seconds as a float since the sampling_start_time
|
26
|
+
attr_reader :sampling_delta
|
27
|
+
|
28
|
+
# An additional hash of data to associate with the metric
|
29
|
+
attr_reader :additional_data
|
30
|
+
|
31
|
+
# The 'name' to associate with the metric
|
32
|
+
attr_reader :name
|
33
|
+
|
34
|
+
#
|
35
|
+
# :call-seq:
|
36
|
+
# Metric.new( 'my_metric' ) -> Metric
|
37
|
+
# Metric.new( 'my_metric', 'foo' => 'bar', 'this' => 42 ) -> Metric
|
38
|
+
#
|
39
|
+
# Create a new ValueMetric giving it a name and additional data.
|
40
|
+
#
|
41
|
+
# +additional_data+ may be anything that follows the +to_hash+ protocol.
|
42
|
+
# +name+ may be anything that follows the +to_s+ protocol.
|
43
|
+
#
|
44
|
+
def initialize( name, additional_data = {} )
|
45
|
+
@sampling_start_time = nil
|
46
|
+
@sampling_start_interval = nil
|
47
|
+
@sampling_delta = 0
|
48
|
+
|
49
|
+
@name = name.to_s
|
50
|
+
@additional_data = additional_data.to_hash
|
51
|
+
end
|
52
|
+
|
53
|
+
#
|
54
|
+
# :call-seq:
|
55
|
+
# metric.sampling_start_time -> Float or nil
|
56
|
+
#
|
57
|
+
# The time at which the first sample was taken.
|
58
|
+
# This is the number of microseconds since UNIX epoch UTC as a Float
|
59
|
+
#
|
60
|
+
# If the metric has not started measuring then the start time is nil.
|
61
|
+
#
|
62
|
+
def sampling_start_time
|
63
|
+
if @sampling_start_interval then
|
64
|
+
@sampling_start_time ||= self.utc_microseconds()
|
65
|
+
else
|
66
|
+
nil
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# :call-seq:
|
72
|
+
# metric.sampling_stop_time -> Float or nil
|
73
|
+
#
|
74
|
+
# The time at which the last sample was taken
|
75
|
+
# This is the number of microseconds since UNIX epoch UTC as a Float
|
76
|
+
#
|
77
|
+
# If the metric has not completely measured at least one thing then
|
78
|
+
# stop time is nil.
|
79
|
+
#
|
80
|
+
# Because accessing the actual 'time of day' is an expesive operation, we
|
81
|
+
# only get the time of day at the beginning of the first measurement and we
|
82
|
+
# keep track of the offset from that point in @sampling_delta.
|
83
|
+
#
|
84
|
+
# When sampling_stop_time is called, the actual time of day is caculated.
|
85
|
+
#
|
86
|
+
def sampling_stop_time
|
87
|
+
if @sampling_delta > 0 then
|
88
|
+
(self.sampling_start_time + (@sampling_delta * 1_000_000))
|
89
|
+
else
|
90
|
+
nil
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
#
|
95
|
+
# :call-seq:
|
96
|
+
# metric.to_hash -> Hash
|
97
|
+
# metric.to_hash
|
98
|
+
#
|
99
|
+
# Convert the metric to a Hash.
|
100
|
+
#
|
101
|
+
def to_hash
|
102
|
+
{ 'sampling_start_time' => self.sampling_start_time,
|
103
|
+
'sampling_stop_time' => self.sampling_stop_time,
|
104
|
+
'additional_data' => self.additional_data,
|
105
|
+
'name' => self.name }
|
106
|
+
end
|
107
|
+
|
108
|
+
#
|
109
|
+
# :call-seq:
|
110
|
+
# metric.utc_microseconds -> Float
|
111
|
+
#
|
112
|
+
# The current time in microseconds from the UNIX Epoch in the UTC
|
113
|
+
#
|
114
|
+
def utc_microseconds
|
115
|
+
Time.now.gmtime.to_f * 1_000_000
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008, 2009 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'thread'
|
7
|
+
|
8
|
+
module Hitimes
|
9
|
+
#
|
10
|
+
# MutexedStats is the start of a threadsafe Stats class. Currently, on MRI
|
11
|
+
# Ruby the Stats object is already threadsafe, so there is no need to use
|
12
|
+
# MutexedStats.
|
13
|
+
#
|
14
|
+
class MutexedStats < Stats
|
15
|
+
def initialize
|
16
|
+
@mutex = Mutex.new
|
17
|
+
end
|
18
|
+
|
19
|
+
# call-seq:
|
20
|
+
# mutex_stat.update( val ) -> nil
|
21
|
+
#
|
22
|
+
# Update the running stats with the new value in a threadsafe manner.
|
23
|
+
#
|
24
|
+
def update( value )
|
25
|
+
@mutex.synchronize do
|
26
|
+
super( value )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
@@ -0,0 +1,53 @@
|
|
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
|
+
# Access to various paths inside the project programatically
|
9
|
+
#
|
10
|
+
module Paths
|
11
|
+
#
|
12
|
+
# :call-seq:
|
13
|
+
# Hitimes::Paths.root_dir -> String
|
14
|
+
#
|
15
|
+
# Returns The full expanded path of the parent directory of +lib+
|
16
|
+
# going up the path from the current file. A trailing File::SEPARATOR
|
17
|
+
# is guaranteed.
|
18
|
+
#
|
19
|
+
def self.root_dir
|
20
|
+
@root_dir ||=(
|
21
|
+
path_parts = ::File.expand_path(__FILE__).split(::File::SEPARATOR)
|
22
|
+
lib_index = path_parts.rindex("lib")
|
23
|
+
@root_dir = path_parts[0...lib_index].join(::File::SEPARATOR) + ::File::SEPARATOR
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# :call-seq:
|
29
|
+
# Hitimes::Paths.lib_path( *args ) -> String
|
30
|
+
#
|
31
|
+
# Returns The full expanded path of the +lib+ directory below
|
32
|
+
# _root_dir_. All parameters passed in are joined onto the
|
33
|
+
# result. A trailing File::SEPARATOR is guaranteed if
|
34
|
+
# _args_ are *not* present.
|
35
|
+
#
|
36
|
+
def self.lib_path(*args)
|
37
|
+
self.sub_path("lib", *args)
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# :call-seq:
|
42
|
+
# Hitimes::Paths.sub_path( sub, *args ) -> String
|
43
|
+
#
|
44
|
+
# Returns the full expanded path of the +sub+ directory below _root_dir. All
|
45
|
+
# _arg_ parameters passed in are joined onto the result. A trailing
|
46
|
+
# File::SEPARATOR is guaranteed if _args_ are *not* present.
|
47
|
+
#
|
48
|
+
def self.sub_path(sub,*args)
|
49
|
+
sp = ::File.join(root_dir, sub) + File::SEPARATOR
|
50
|
+
sp = ::File.join(sp, *args) if args
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2008, 2009 Jeremy Hinegardner
|
3
|
+
# All rights reserved. See LICENSE and/or COPYING for details.
|
4
|
+
#++
|
5
|
+
|
6
|
+
require 'stringio'
|
7
|
+
module Hitimes
|
8
|
+
class Stats
|
9
|
+
# A list of the available stats
|
10
|
+
STATS = %w[ count max mean min rate stddev sum sumsq ]
|
11
|
+
|
12
|
+
#
|
13
|
+
# call-seq:
|
14
|
+
# stat.to_hash -> Hash
|
15
|
+
# stat.to_hash( %w[ count max mean ]) -> Hash
|
16
|
+
#
|
17
|
+
# return a hash of the stats. By default this returns a hash of all stats
|
18
|
+
# but passing in an array of items will limit the stats returned to only
|
19
|
+
# those in the Array.
|
20
|
+
#
|
21
|
+
# If passed in an empty array or nil to to_hash then STATS is assumed to be
|
22
|
+
# the list of stats to return in the hash.
|
23
|
+
#
|
24
|
+
def to_hash( *args )
|
25
|
+
h = {}
|
26
|
+
args = [ args ].flatten
|
27
|
+
args = STATS if args.empty?
|
28
|
+
args.each do |meth|
|
29
|
+
h[meth] = self.send( meth )
|
30
|
+
end
|
31
|
+
return h
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# call-seq:
|
36
|
+
# stat.to_json -> String
|
37
|
+
# stat.to_json( *args ) -> String
|
38
|
+
#
|
39
|
+
# return a json string of the stats. By default this returns a json string
|
40
|
+
# of all the stats. If an array of items is passed in, those that match the
|
41
|
+
# known stats will be all that is included in the json output.
|
42
|
+
#
|
43
|
+
def to_json( *args )
|
44
|
+
h = to_hash( *args )
|
45
|
+
a = []
|
46
|
+
s = StringIO.new
|
47
|
+
|
48
|
+
s.print "{ "
|
49
|
+
h.each_pair do |k,v|
|
50
|
+
a << "\"#{k}\": #{v}"
|
51
|
+
end
|
52
|
+
s.print a.join(", ")
|
53
|
+
s.print "}"
|
54
|
+
return s.string
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|