package cc.blynk.server.core.stats;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import static java.lang.Math.*;
/**
* copy paste from codahale metrics
*/
public class Meter {
private static final int INTERVAL = 5;
private static final long TICK_INTERVAL = TimeUnit.SECONDS.toNanos(INTERVAL);
private static final double SECONDS_PER_MINUTE = 60.0;
private static final int ONE_MINUTE = 1;
private static final double M1_ALPHA = 1 - exp(-INTERVAL / SECONDS_PER_MINUTE / ONE_MINUTE);
private final EWMA m1Rate = new EWMA(M1_ALPHA, INTERVAL, TimeUnit.SECONDS);
private final LongAdder count = new LongAdder();
private final AtomicLong lastTick;
/**
* Creates a new {@link Meter}.
*
*/
public Meter() {
this.lastTick = new AtomicLong(System.nanoTime());
}
/**
* Mark the occurrence of a given number of events.
*
* @param n the number of events
*/
public void mark(long n) {
tickIfNecessary();
count.add(n);
m1Rate.update(n);
}
private void tickIfNecessary() {
final long oldTick = lastTick.get();
final long newTick = System.nanoTime();
final long age = newTick - oldTick;
if (age > TICK_INTERVAL) {
final long newIntervalStartTick = newTick - age % TICK_INTERVAL;
if (lastTick.compareAndSet(oldTick, newIntervalStartTick)) {
final long requiredTicks = age / TICK_INTERVAL;
for (long i = 0; i < requiredTicks; i++) {
m1Rate.tick();
}
}
}
}
public long getCount() {
return count.sum();
}
public double getOneMinuteRate() {
tickIfNecessary();
return m1Rate.getRate(TimeUnit.SECONDS);
}
}