/* *************************************************************************************** * Copyright (C) 2006 EsperTech, Inc. All rights reserved. * * http://www.espertech.com/esper * * http://www.espertech.com * * ---------------------------------------------------------------------------------- * * The software in this package is published under the terms of the GPL license * * a copy of which has been included with this distribution in the license.txt file. * *************************************************************************************** */ package com.espertech.esper.example.benchmark.server; import java.util.concurrent.atomic.AtomicBoolean; /** * A Stats instance gathers percentile based on a given histogram * This class is thread unsafe. * * @author Alexandre Vasseur http://avasseur.blogspot.com * @see com.espertech.esper.example.benchmark.server.StatsHolder for thread safe access * Use createAndMergeFrom(proto) for best effort merge of this instance into the proto instance * (no read / write lock is performed so the actual counts are a best effort) */ public class Stats { private AtomicBoolean mustReset = new AtomicBoolean(false); final public String name; final public String unit; private long count; private double avg; private int[] histogram; private long[] counts; public Stats(String name, String unit, int... hists) { //10, 20, (20+ implicit) this.name = name; this.unit = unit; histogram = new int[hists.length + 1]; //we add one slot for the implicit 20+ System.arraycopy(hists, 0, histogram, 0, hists.length); histogram[histogram.length - 1] = hists[hists.length - 1] + 1; counts = new long[histogram.length]; for (int i = 0; i < counts.length; i++) counts[i] = 0; } /** * Use this method to merge this stat instance into a prototype one (for thread safe read only snapshoting) */ public static Stats createAndMergeFrom(Stats model) { Stats r = new Stats(model.name, model.unit, 0); r.histogram = new int[model.histogram.length]; System.arraycopy(model.histogram, 0, r.histogram, 0, model.histogram.length); r.counts = new long[model.histogram.length]; r.merge(model); return r; } public void update(long ns) { if (mustReset.compareAndSet(true, false)) internal_reset(); count++; avg = (avg * (count - 1) + ns) / count; if (ns >= histogram[histogram.length - 1]) { counts[counts.length - 1]++; } else { int index = 0; for (int level : histogram) { if (ns < level) { counts[index]++; break; } index++; } } } public void dump() { System.out.println("---Stats - " + name + " (unit: " + unit + ")"); System.out.printf(" Avg: %.0f #%d\n", avg, count); int index = 0; long lastLevel = 0; long occurCumul = 0; for (long occur : counts) { occurCumul += occur; if (index != counts.length - 1) { System.out.printf(" %7d < %7d: %6.2f%% %6.2f%% #%d\n", lastLevel, histogram[index], (float) occur / count * 100, (float) occurCumul / count * 100, occur); lastLevel = histogram[index]; } else { System.out.printf(" %7d < more: %6.2f%% %6.2f%% #%d\n", lastLevel, (float) occur / count * 100, 100f, occur); } index++; } } public void merge(Stats stats) { // we assume same histogram - no check done here count += stats.count; avg = ((avg * count) + (stats.avg * stats.count)) / (count + stats.count); for (int i = 0; i < counts.length; i++) { counts[i] += stats.counts[i]; } } private void internal_reset() { count = 0; avg = 0; for (int i = 0; i < counts.length; i++) counts[i] = 0; } public void reset() { mustReset.set(true); } public static void main(String[] args) { Stats stats = new Stats("a", "any", 10, 20); stats.update(1); stats.update(2); stats.update(10); stats.update(15); stats.update(25); //stats.dump(); Stats stats2 = new Stats("b", "any", 10, 20); stats2.update(1); stats.merge(stats2); stats.dump(); long l = 100; long l2 = 3; System.out.println("" + (float) l / l2); System.out.printf("%15.4f", (float) l / l2); } }