Permalink
Browse files

week-end project is still a thing

  • Loading branch information...
1 parent 01b2bf7 commit 7b3c839fe730a6135cdc3af77a77a3bf4496af69 @cyberdelia committed Mar 18, 2012
View
@@ -13,4 +13,5 @@ coverage/
.tox/
.DS_Store
.idea
-.venv
+.venv
+htmlcov/
View
@@ -0,0 +1,19 @@
+from metrology.registry import registry
+
+
+class Metrology(object):
+ @classmethod
+ def get(cls, name):
+ return registry.get(name)
+
+ @classmethod
+ def counter(cls, name):
+ return registry.counter(name)
+
+ @classmethod
+ def meter(cls, name):
+ return registry.meter(name)
+
+ @classmethod
+ def gauge(cls, name, gauge):
+ return registry.gauge(name, gauge)
View
@@ -0,0 +1,6 @@
+class MetrologyException(Exception):
+ pass
+
+
+class ArgumentException(MetrologyException):
+ pass
@@ -0,0 +1,6 @@
+# -*- flake8: noqa -*-
+from metrology.instruments.counter import Counter
+from metrology.instruments.gauge import Gauge
+from metrology.instruments.histogram import Histogram, HistogramUniform, HistogramExponentiallyDecaying
+from metrology.instruments.meter import Meter
+from metrology.instruments.timer import Timer, UtilizationTimer
@@ -0,0 +1,19 @@
+from atomic import Atomic
+
+
+class Counter(object):
+ def __init__(self):
+ self._count = Atomic(0)
+
+ def increment(self, value=1):
+ self._count.value += value
+
+ def decrement(self, value=1):
+ self._count.value -= value
+
+ def clear(self):
+ self._count.value = 0
+
+ @property
+ def count(self):
+ return self._count.value
@@ -0,0 +1,40 @@
+from __future__ import division
+
+import math
+
+from atomic import Atomic
+
+
+class Gauge(object):
+ def value(self):
+ raise NotImplementedError
+
+
+class RatioGauge(Gauge):
+ def numerator(self):
+ raise NotImplementedError
+
+ def denominator(self):
+ raise NotImplementedError
+
+ def value(self):
+ d = self.denominator()
+ if math.isnan(d) or math.isinf(d) or d == 0.0 or d == 0:
+ return float('nan')
+ return self.numerator() / d
+
+
+class PercentGauge(RatioGauge):
+ def value(self):
+ value = super(PercentGauge, self).value()
+ return value * 100
+
+
+class ToggleGauge(Gauge):
+ _value = Atomic(1)
+
+ def value(self):
+ try:
+ return self._value.get()
+ finally:
+ self._value.set(0)
@@ -0,0 +1,119 @@
+from __future__ import division
+
+from atomic import Atomic
+
+from metrology.stats.sample import UniformSample, ExponentiallyDecayingSample
+
+
+class Histogram(object):
+ DEFAULT_SAMPLE_SIZE = 1028
+ DEFAULT_ALPHA = 0.015
+
+ def __init__(self, sample):
+ self.sample = sample
+ self.counter = Atomic(0)
+ self.minimum = Atomic()
+ self.maximum = Atomic()
+ self.sum = Atomic(0)
+ self.var = Atomic([-1, 0])
+
+ def clear(self):
+ self.sample.clear()
+ self.counter.value = 0
+ self.minimum.value = None
+ self.maximum.value = None
+ self.sum.value = 0
+ self.var.value = [-1, 0]
+
+ def update(self, value):
+ with self.counter:
+ self.counter.value += 1
+ self.sample.update(value)
+ self.max = value
+ self.min = value
+ with self.sum:
+ self.sum.value += value
+ self.update_variance(value)
+
+ @property
+ def snapshot(self):
+ return self.sample.snapshot()
+
+ @property
+ def count(self):
+ return self.counter.value
+
+ def get_max(self):
+ if self.counter.value > 0:
+ return self.maximum.value
+ return 0.0
+
+ def set_max(self, potential_max):
+ done = False
+ while not done:
+ current_max = self.maximum.value
+ done = (current_max is not None and current_max >= potential_max) \
+ or self.maximum.compare_and_swap(current_max, potential_max)
+
+ max = property(get_max, set_max)
+
+ def get_min(self):
+ if self.counter.value > 0:
+ return self.minimum.value
+ return 0.0
+
+ def set_min(self, potential_min):
+ done = False
+ while not done:
+ current_min = self.minimum.value
+ done = (current_min is not None and current_min <= potential_min) \
+ or self.minimum.compare_and_swap(current_min, potential_min)
+
+ min = property(get_min, set_min)
+
+ @property
+ def mean(self):
+ if self.counter.value > 0:
+ return self.sum.value / self.counter.value
+ return 0.0
+
+ @property
+ def stddev(self):
+ if self.counter.value > 0:
+ return self.var.value
+ return 0.0
+
+ @property
+ def variance(self):
+ if self.counter.value <= 1:
+ return 0.0
+ return self.var.value[1] / (self.counter.value - 1)
+
+ def update_variance(self, value):
+ with self.var:
+ old_values = self.var.value
+ if old_values[0] == -1:
+ new_values = (value, 0)
+ else:
+ old_m = old_values[0]
+ old_s = old_values[1]
+
+ new_m = old_m + ((value - old_m) / self.counter.value)
+ new_s = old_s + ((value - old_m) * (value - new_m))
+
+ new_values = (new_m, new_s)
+
+ self.var.value = new_values
+ return new_values
+
+
+class HistogramUniform(Histogram):
+ def __init__(self):
+ sample = UniformSample(self.DEFAULT_SAMPLE_SIZE)
+ super(HistogramUniform, self).__init__(sample)
+
+
+class HistogramExponentiallyDecaying(Histogram):
+ def __init__(self):
+ sample = ExponentiallyDecayingSample(self.DEFAULT_SAMPLE_SIZE, self.DEFAULT_ALPHA)
+ super(HistogramExponentiallyDecaying, self).__init__(sample)
@@ -0,0 +1,69 @@
+import time
+from threading import Thread
+
+from atomic import Atomic
+
+from metrology.stats import EWMA
+
+
+class Meter(object):
+ def __init__(self, average_class=EWMA):
+ self.counter = Atomic(0)
+ self.start_time = time.time()
+
+ self.m1_rate = EWMA.m1()
+ self.m5_rate = EWMA.m5()
+ self.m15_rate = EWMA.m15()
+
+ self.running = True
+
+ def timer():
+ while self.running:
+ time.sleep(average_class.INTERVAL)
+ self.tick()
+
+ self.thread = Thread(target=timer)
+ self.thread.start()
+
+ @property
+ def count(self):
+ return self.counter.value
+
+ def clear(self):
+ self.counter.value = 0
+ self.start_time = time.time()
+
+ self.m1_rate.clear()
+ self.m5_rate.clear()
+ self.m15_rate.clear()
+
+ def mark(self, value=1):
+ with self.counter:
+ self.counter.value += value
+ self.m1_rate.update(value)
+ self.m5_rate.update(value)
+ self.m15_rate.update(value)
+
+ def tick(self):
+ self.m1_rate.tick()
+ self.m5_rate.tick()
+ self.m15_rate.tick()
+
+ def one_minute_rate(self):
+ return self.m1_rate.rate
+
+ def five_minute_rate(self):
+ return self.m5_rate.rate
+
+ def fifteen_minute_rate(self):
+ return self.m15_rate.rate
+
+ def mean_rate(self):
+ if self.counter.value == 0:
+ return 0.0
+ else:
+ elapsed = time.time() - self.start_time
+ return self.counter.value / elapsed
+
+ def stop(self):
+ self.running = False
@@ -0,0 +1,98 @@
+import time
+
+from metrology.instruments.histogram import HistogramExponentiallyDecaying
+from metrology.instruments.meter import Meter
+
+
+class Timer(object):
+ def __init__(self, histogram=HistogramExponentiallyDecaying):
+ self.meter = Meter()
+ self.histogram = histogram()
+
+ def clear(self):
+ self.meter.clear()
+ self.histogram.clear()
+
+ def update(self, duration):
+ if duration >= 0:
+ self.meter.mark()
+ self.histogram.update(duration)
+
+ @property
+ def snapshot(self):
+ return self.histogram.snapshot
+
+ def __enter__(self):
+ self.start_time = time.time()
+ return self
+
+ def __exit__(self, type, value, callback):
+ self.update(time.time() - self.start_time)
+
+ @property
+ def count(self):
+ return self.histogram.count
+
+ @property
+ def one_minute_rate(self):
+ return self.meter.one_minute_rate()
+
+ def five_minute_rate(self):
+ return self.meter.five_minute_rate()
+
+ def fifteen_minute_rate(self):
+ return self.meter.fifteen_minute_rate()
+
+ @property
+ def mean_rate(self):
+ return self.meter.mean_rate
+
+ @property
+ def min(self):
+ return self.histogram.min
+
+ @property
+ def max(self):
+ return self.histogram.max
+
+ @property
+ def mean(self):
+ return self.histogram.mean
+
+ @property
+ def stddev(self):
+ return self.histogram.stddev
+
+ def stop(self):
+ self.meter.stop()
+
+
+class UtilizationTimer(Timer):
+ def __init__(self):
+ super(UtilizationTimer, self).__init__()
+ self.duration_meter = Meter()
+
+ def clear(self):
+ super(UtilizationTimer, self).clear()
+ self.duration_meter.clear()
+
+ def update(self, duration):
+ super(UtilizationTimer, self).update(duration)
+ if duration >= 0:
+ self.duration_meter.mark(duration)
+
+ def one_minute_utilization(self):
+ return self.duration_meter.one_minute_rate()
+
+ def five_minute_utilization(self):
+ return self.duration_meter.five_minute_rate()
+
+ def fifteen_minute_utilization(self):
+ return self.duration_meter.fifteen_minute_rate()
+
+ def mean_utilization(self):
+ return self.duration_meter.mean_rate()
+
+ def stop(self):
+ super(UtilizationTimer, self).stop()
+ self.duration_meter.stop()
Oops, something went wrong.

0 comments on commit 7b3c839

Please sign in to comment.