Permalink
Browse files

Add histogram, timer, and a test

  • Loading branch information...
1 parent d57d564 commit 995491585f4bf2d7b41955af738791093d383564 @eric committed Jan 31, 2012
Showing with 198 additions and 7 deletions.
  1. +2 −0 .gitignore
  2. +5 −1 Gemfile
  3. +20 −0 Gemfile.lock
  4. +2 −2 Rakefile
  5. +89 −0 lib/metriks/histogram.rb
  6. +49 −0 lib/metriks/timer.rb
  7. +4 −4 lib/metriks/uniform_sample.rb
  8. +21 −0 test/counter_test.rb
  9. +6 −0 test/test_helper.rb
View
@@ -1 +1,3 @@
*~
+.bundle
+vendor/bundle
View
@@ -1,3 +1,7 @@
source :rubygems
-gemspec
+gemspec
+
+group :test do
+ gem 'turn'
+end
View
@@ -0,0 +1,20 @@
+PATH
+ remote: .
+ specs:
+ metriks (0.0)
+ atomic (~> 0.0.9)
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ ansi (1.4.2)
+ atomic (0.0.9)
+ turn (0.8.3)
+ ansi
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ metriks!
+ turn
View
@@ -48,15 +48,15 @@ task :default => :test
require 'rake/testtask'
Rake::TestTask.new(:test) do |test|
test.libs << 'lib' << 'test'
- test.pattern = 'test/**/test_*.rb'
+ test.pattern = 'test/**/*_test.rb'
test.verbose = true
end
desc "Generate RCov test coverage and open in your browser"
task :coverage do
require 'rcov'
sh "rm -fr coverage"
- sh "rcov test/test_*.rb"
+ sh "rcov test/*_test.rb"
sh "open coverage/index.html"
end
View
@@ -0,0 +1,89 @@
+
+class Metriks::Histogram
+ DEFAULT_SAMPLE_SIZE = 1028
+ DEFAULT_ALPHA = 0.015
+
+ def initialize(sample)
+ @sample = sample
+ @count = Atomic.new(0)
+ @min = Atomic.new(nil)
+ @max = Atomic.new(nil)
+ @sum = Atomic.new(0)
+ @variance = Atomic.new([ -1, 0 ])
+ end
+
+ def update(value)
+ @count.update { |v| v + 1 }
+ @sample.update(value)
+ self.max = value
+ self.min = value
+ @sum.update { |v| v + value }
+ update_variance(value)
+ end
+
+ def count
+ @count.value
+ end
+
+ def max
+ count > 0 ? @max.value : 0.0
+ end
+
+ def min
+ count > 0 ? @min.value : 0.0
+ end
+
+ def mean
+ count > 0 ? sum.value / count : 0.0
+ end
+
+ def stddev
+ count > 0 ? variance : 0.0
+ end
+
+ def variance
+ count < = 1 ? 0.0 : @variance.value[1] / (count - 1)
+ end
+
+ def max=(potential_max)
+ done = false
+
+ while !done
+ current_max = @max.value
+ done = (!current_max.nil? && current_max >= potential_max) || @max.compare_and_swap(current_max, potential_max)
+ end
+ end
+
+ def min=(potential_min)
+ done = false
+
+ while !done
+ current_min = @min.value
+ done = (!current_min.nil? && current_min <= potential_min) || @min.compare_and_swap(current_min, potential_min)
+ end
+ end
+
+ def update_variance(value)
+ done = false
+
+ while !done
+ old_values = @variance.value
+ new_values = Array.new(2)
+ if old_values[0] == -1
+ new_values[0] = value
+ new_values[1] = 0
+ else
+ old_m = old_values[0]
+ old_s = old_values[1]
+
+ new_m = old_m + ((value - old_m) / count)
+ new_s = old_s + ((value - old_m) * (value - new_m))
+
+ new_values[0] = new_m
+ new_values[1] = new_s
+ end
+
+ done = @variance.compare_and_swap(old_values, new_values)
+ end
+ end
+end
View
@@ -0,0 +1,49 @@
+require 'atomic'
+
+class Metriks::Timer
+ def initialize
+ @meter = Meter.new
+ @count = Atomic.new(0)
+ end
+
+ def update(duration)
+ if duration >= 0
+ @meter.mark
+ end
+ end
+
+ def time(callable = nil, &block)
+ callable ||= block
+ start_time = Time.now
+
+ begin
+ return callable.call
+ ensure
+ update(Time.now - start_time)
+ end
+ end
+
+ def count
+ @meter.count
+ end
+
+ def one_minute_rate
+ @meter.one_minute_rate
+ end
+
+ def five_minute_rate
+ @meter.five_minute_rate
+ end
+
+ def fifteen_minute_rate
+ @meter.fifteen_minute_rate
+ end
+
+ def mean_rate
+ @meter.mean_rate
+ end
+
+ def stop
+ @meter.stop
+ end
+end
@@ -5,22 +5,22 @@ def initialize(reservoir_size)
@values = Array.new(reservoir_size, 0)
@count = Atomic.new(0)
end
-
+
def clear
@values.length.times do |idx|
@values[idx] = 0
end
@count.value = 0
end
-
+
def size
count = @count.value
count > @values.length ? @values.length : count
end
-
+
def update(value)
new_count = @count.update { |v| v + 1 }
-
+
if new_count <= @values.length
@values[new_count - 1] = value
else
View
@@ -0,0 +1,21 @@
+require 'test_helper'
+
+require 'metriks/counter'
+
+class CounterTest < Test::Unit::TestCase
+ def setup
+ @counter = Metriks::Counter.new
+ end
+
+ def test_increment
+ @counter.increment
+
+ assert_equal 1, @counter.count
+ end
+
+ def test_increment_by_more
+ @counter.increment 10
+
+ assert_equal 10, @counter.count
+ end
+end
View
@@ -0,0 +1,6 @@
+require 'test/unit'
+require 'pp'
+
+require 'turn'
+
+require 'metriks'

0 comments on commit 9954915

Please sign in to comment.