File: histogram.rb

package info (click to toggle)
ruby-metriks 0.9.9.8-3.1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 288 kB
  • sloc: ruby: 1,877; makefile: 2
file content (116 lines) | stat: -rw-r--r-- 2,466 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
require 'atomic'
require 'metriks/uniform_sample'
require 'metriks/exponentially_decaying_sample'

module Metriks
  class Histogram
    DEFAULT_SAMPLE_SIZE = 1028
    DEFAULT_ALPHA = 0.015

    def self.new_uniform
      new(Metriks::UniformSample.new(DEFAULT_SAMPLE_SIZE))
    end

    def self.new_exponentially_decaying
      new(Metriks::ExponentiallyDecayingSample.new(DEFAULT_SAMPLE_SIZE, DEFAULT_ALPHA))
    end

    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 clear
      @sample.clear
      @count.value = 0
      @min.value = nil
      @max.value = nil
      @sum.value = 0
      @variance.value = [ -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 snapshot
      @sample.snapshot
    end

    def count
      @count.value
    end

    def sum
      @sum.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.5 : 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)
      @variance.update do |old_values|
        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

        new_values
      end
    end
  end
end