package netflix.ocelli.stats; import netflix.ocelli.util.AtomicDouble; import netflix.ocelli.util.SingleMetric; import rx.functions.Func0; public class ExponentialAverage implements SingleMetric<Long> { private final double k; private final AtomicDouble ema; private final double initial; public static Func0<SingleMetric<Long>> factory(final int N, final double initial) { return new Func0<SingleMetric<Long>>() { @Override public SingleMetric<Long> call() { return new ExponentialAverage(N, initial); } }; } public ExponentialAverage(int N, double initial) { this.initial = initial; this.k = 2.0/(double)(N+1); this.ema = new AtomicDouble(initial); } @Override public void add(Long sample) { double next; double current; do { current = ema.get(); next = sample * k + current * (1-k); } while(!ema.compareAndSet(current, next)); } @Override public Long get() { return (long)ema.get(); } @Override public void reset() { ema.set(initial); } }