Skip to content

Instantly share code, notes, and snippets.

@matschaffer
Created December 3, 2015 04:46
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save matschaffer/210b1d08112620bb905c to your computer and use it in GitHub Desktop.
Save matschaffer/210b1d08112620bb905c to your computer and use it in GitHub Desktop.
require 'gsl'
require 'time'
module Diskalerter
class ThresholdEstimator
attr_reader :timestamps, :signal, :threshold, :now
# timestamps - a list of timestamps in epoch milliseconds
# signal - a list of values for the provided timestamps
# threshold - the "exhaustion" threshold (e.g., 100 for a percentage signal)
def initialize(timestamps, signal, threshold)
@timestamps = timestamps
@signal = signal
@threshold = threshold
@now = Time.now.to_i
end
def alertable?
now < intersect && intersect < warning_threshold
end
def will_intersect?
now < intersect && intersect < never
end
def intersect
x_intersect, slope = linear_fit
(threshold - x_intersect) / slope
end
def linear_fit
return @linear_fit if @linear_fit
timestamps, signal = filtered_data
x = GSL::Vector[*timestamps]
y = GSL::Vector[*signal]
@linear_fit = GSL::Fit.linear(x, y)
end
def warning_threshold
now + one_week
end
def one_week
3600 * 24 * 7
end
def five_years
one_week * 52 * 5
end
def never
now + five_years
end
def intersect_time
Time.at(intersect)
end
def intersect_days
(intersect - now) / 24 / 3600
end
def intersect_milliseconds
(intersect - now) * 1000
end
def intersect_time_string
if will_intersect?
'%s (%0.2f days)' % [intersect_time.iso8601, intersect_days]
else
'Never'
end
end
private
def filtered_data
timestamps.map { |t| t / 1000 }.zip(signal).reject { |pair| pair[1].nil? }.transpose
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment