/*
* Copyright (C) ${year} Omry Yadan <${email}>
* All rights reserved.
*
* See https://github.com/omry/banana/blob/master/BSD-LICENSE for licensing information
*/
package net.yadan.utils;
/**
* Created on 23/02/2004
*
* @author Omry Yadan
*/
public class RateCounter {
private int m_averageOverNumSeconds;
int m_seconds[];
int m_currentSecond;
float m_ticksPerSecond;
// the actual number of seconds used in the array.
private int m_actualArraySize;
// the index of the current second in the seconds array.
private int m_pointer;
private long m_numTicks;
public RateCounter(int numSeconds) {
init(numSeconds);
}
/**
* @param numSeconds
*/
private synchronized void init(int numSeconds) {
m_averageOverNumSeconds = numSeconds;
m_seconds = new int[m_averageOverNumSeconds];
m_currentSecond = -1;
m_ticksPerSecond = -1;
m_actualArraySize = 0;
m_pointer = 0;
}
public void tick() {
tick(1);
}
public void tick(int ticks) {
tick(ticks, System.currentTimeMillis());
}
/**
* @param ticks number of ticks
* @param timestamp logical time this even happened. this can be used to rate count historical timestamped data
*/
public synchronized void tick(int ticks, long time) {
m_numTicks += ticks;
int second = (int) (time / 1000);
if (second != m_currentSecond && m_currentSecond != -1) // second changed
// and not first
{
m_actualArraySize = Math.min(m_actualArraySize + 1, m_seconds.length);
m_pointer = (m_pointer + 1) % m_seconds.length;
m_seconds[m_pointer] = ticks;
int c = 0;
for (int i = 0; i < m_actualArraySize; i++) {
if (i != m_pointer) {
c += m_seconds[i];
}
}
if (m_actualArraySize > 2) {
m_ticksPerSecond = c / (float) (m_actualArraySize - 1);
}
// System.out.print("counter = ");
// for (int i = 0 ; i < m_actualArraySize ; i++)
// {
// System.out.print(m_seconds[i] + ",");
// }
// System.out.println("tps : " + getTicksPerSecond());
} else // same second
{
m_seconds[m_pointer] += ticks;
}
m_currentSecond = second;
}
public synchronized float getTicksPerSecond() {
return m_ticksPerSecond;
}
/**
*
*/
public void reset() {
init(m_averageOverNumSeconds);
}
public long getNumTicks() {
return m_numTicks;
}
private static class Ticker {
private final RateCounter m_rc;
private final int m_intervalMs;
private final int m_numPulse;
private boolean m_running = false;
private final Thread m_thread;
public Ticker(int intervalMs, int numPulse) {
System.out.println("Interval " + intervalMs + ", pulse " + numPulse
+ ", avg = " + (numPulse / (intervalMs / 1000f)) + " pulses/sec");
m_rc = new RateCounter(5);
m_intervalMs = intervalMs;
m_numPulse = numPulse;
m_thread = new Thread() {
@Override
public void run() {
while (m_running) {
m_rc.tick(m_numPulse);
try {
sleep(m_intervalMs);
} catch (InterruptedException e) {
}
}
}
};
m_running = true;
m_thread.start();
}
public void stop() {
m_running = false;
m_thread.interrupt();
try {
m_thread.join();
} catch (InterruptedException e) {
}
System.out.println("Ticker exited");
}
}
public static void main(String[] args) {
System.out.println("Testing rate counter");
// drive(new Ticker(1000, 1), 20);
drive(new Ticker(10000, 10), 30);
}
private static void drive(Ticker t, int seconds) {
while (seconds-- > 0) {
try {
Thread.sleep(1000);
System.out.println("TPS : " + t.m_rc.getTicksPerSecond());
} catch (InterruptedException e) {
}
}
t.stop();
}
}