Symphony::

Statistics

module

A collection of statistics functions for various Symphony systems. Special thanks to Justin Z. Smith <justin@statisticool.com> for the maths. Good luck with your search for economic collapse in applesauce!

Constants

DEFAULT_SAMPLE_SIZE

The default number of samples to keep

Attributes

sample_size[RW]

The number of samples to keep for analysis, and required before trending is performed.

samples[R]

Samples of the number of pending jobs

Public Class Methods

anchor
new( * )

Set up some instance variables for tracking statistical info when the object is created.

# File lib/symphony/statistics.rb, line 18
def initialize( * )
        super
        @samples = []
        @sample_size = DEFAULT_SAMPLE_SIZE
        @counter = 0
end

Public Instance Methods

anchor
add_sample( value )

Add the specified value as a sample for the current time.

# File lib/symphony/statistics.rb, line 36
def add_sample( value )
        @samples << [ Time.now.to_f, value ]
        @samples.shift( @samples.size - self.sample_size ) if @samples.size > self.sample_size
        @counter = ( @counter + 1 ) % 3
end
anchor
calculate_trend()

Predict the likelihood that an upward trend will continue based on linear regression analysis of the given samples. If the value returned is >= 3.0, the values are statistically trending upwards, which in Symphony's case means that the workers are not handling the incoming work.

# File lib/symphony/statistics.rb, line 66
def calculate_trend
        return 0 unless self.samples.size >= self.sample_size
        # Loggability[ Symphony ].debug "%d samples of required %d" % [ self.samples.size, self.sample_size ]

        x_vec, y_vec = self.samples.transpose

        y_avg = y_vec.inject( :+ ).to_f / y_vec.size
        x_avg = x_vec.inject( :+ ).to_f / x_vec.size

        # Find slope and y-intercept.
        #
        n = d = 0
        samples.each do |x, y_val|
                xv = x - x_avg
                n  = n + ( xv * ( y_val - y_avg ) )
                d  = d + ( xv ** 2 )
        end

        slope = n/d
        y_intercept = y_avg - ( slope * x_avg )

        # Find stderr.
        #
        r = s = 0
        samples.each do |x, y_val|
                yv = ( slope * x ) + y_intercept
                r  = r + ( (y_val - yv) ** 2 )
                s  = s + ( (x - x_avg) ** 2 )
        end

        stde = Math.sqrt( (r / ( samples.size - 2 )) / s )

        # Loggability[ Symphony ].debug "  job sampling trend is: %f" %  [ slope / stde ] if
        #     @counter.zero?

        return slope / stde
end
anchor
mean_jobcount()

Return the mean of the job count samples.

# File lib/symphony/statistics.rb, line 56
def mean_jobcount
        return 0 unless self.samples.size >= self.sample_size
        return @samples.map( &:last ).reduce( :+ ) / @samples.length.to_f
end
anchor
sample_values_decreasing?()

Returns true if the samples gathered so far indicate a downwards trend.

# File lib/symphony/statistics.rb, line 50
def sample_values_decreasing?
        return self.calculate_trend < -3
end
anchor
sample_values_increasing?()

Returns true if the samples gathered so far indicate an upwards trend.

# File lib/symphony/statistics.rb, line 44
def sample_values_increasing?
        return self.calculate_trend > 3
end