/* * NOTE: This copyright does *not* cover user programs that use HQ * program services by normal system calls through the application * program interfaces provided as part of the Hyperic Plug-in Development * Kit or the Hyperic Client Development Kit - this is merely considered * normal use of the program, and does *not* fall under the heading of * "derived work". * * Copyright (C) [2004, 2005, 2006], Hyperic, Inc. * This file is part of HQ. * * HQ is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. This program is distributed * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ package org.hyperic.util.stats; /** * The StatsCollector is a class used to calculate metrics based on a * series of events. Events consist of a value and a timestamp. * * This class is synchronized. */ public class StatsCollector { private final Object LOCK = new Object(); private long[] _timestamps; private double[] _values; private int _start; // Head of ringbuffer -- points at oldest ent private int _numEnts; // # entries used in the arrays private int _size; // Size allocated for the arrays // Running stats private double _total; // Sum of everything in the values array /** * Create a new collector which is able to internally store 'size' * elements. */ public StatsCollector(int size) { _timestamps = new long[size]; _values = new double[size]; _start = 0; _numEnts = 0; _size = size; _total = 0; } /** * Add a value to the collection. Old values will be evicted from the * collection if the addition would exceed the internal size. */ public void add(double value, long timestamp) { synchronized (LOCK) { if (_numEnts == _size) { // Remove oldest entry at _values[_start] _total -= _values[_start]; _values[_start] = value; _timestamps[_start] = timestamp; _start++; if (_start == _size) _start = 0; } else { int insertIdx = _start + _numEnts; _values[insertIdx] = value; _timestamps[insertIdx] = timestamp; _numEnts++; } _total += value; } } /** * Get the sum of all values. */ public double getTotal() { synchronized (LOCK) { return _total; } } /** * Get the timestamp of the oldest entry (or -1 if there are no entries) */ public long getOldestTime() { synchronized (LOCK) { if (_numEnts == 0) return -1; return _timestamps[_start]; } } /** * Get the timestamp of the newest entry (or -1 if there are no entries) */ public long getNewestTime() { synchronized (LOCK) { if (_numEnts == 0) return -1; int idx = _start + (_numEnts - 1); if (idx >= _size) idx -= _size; return _timestamps[idx]; } } /** * Get the value per timestamp increment. I.e: * * getTotal() / (endTime - getOldestTime()) */ public double valPerTimestamp(long newestTime) { synchronized (LOCK) { if (_numEnts < 2) return Double.NaN; long runtime = newestTime - getOldestTime(); return getTotal() / runtime; } } public double valPerTimestamp() { synchronized (LOCK) { return valPerTimestamp(getNewestTime()); } } /** * Get the # of elements in the collector */ public int getSize() { synchronized (LOCK) { return _numEnts; } } public String dump() { synchronized (LOCK) { StringBuffer res = new StringBuffer(); int idx = _start; res.append("Size=" + _size + " Start=" + _start + " numEnts=" + _numEnts + " valPerTimestamp=" + valPerTimestamp() + " oldest=" + getOldestTime() + " newest=" + getNewestTime() + "\n"); for (int i=0; i<_numEnts; i++) { res.append("Value[" + idx + "] val=" + _values[idx] + " ts=" + _timestamps[idx] + "\n"); idx++; if (idx == _size) idx = 0; } return res.toString(); } } public static void main(String[] args) { StatsCollector x = new StatsCollector(2); x.add(100, 1); System.out.println(x.dump()); x.add(200, 2); System.out.println(x.dump()); x.add(300, 3); System.out.println(x.dump()); x.add(400, 4); System.out.println(x.dump()); } }