mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2024-11-24 03:25:29 +01:00
Added a way to compute a "histogram" (ordered by time slices).
This allows us to see snapshots of the online statistics algorihm.
This commit is contained in:
parent
300d3c2475
commit
839c186609
@ -0,0 +1,125 @@
|
||||
package com.comphenix.protocol.timing;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
* Represents an online algortihm of computing histograms over time.
|
||||
* @author Kristian
|
||||
*/
|
||||
public class HistogramStream extends OnlineComputation {
|
||||
/**
|
||||
* Each bin in the histogram, indexed by time.
|
||||
*/
|
||||
protected List<StatisticsStream> bins;
|
||||
|
||||
/**
|
||||
* The current statistics stream we are updating.
|
||||
*/
|
||||
protected StatisticsStream current;
|
||||
|
||||
/**
|
||||
* The maximum number of observations in each bin.
|
||||
*/
|
||||
protected int binWidth;
|
||||
|
||||
/**
|
||||
* The number of total observations.
|
||||
*/
|
||||
protected int count;
|
||||
|
||||
/**
|
||||
* Construct a new histogram stream which splits up every observation in different bins, ordered by time.
|
||||
* @param binWidth - maximum number of observations in each bin.
|
||||
*/
|
||||
public HistogramStream(int binWidth) {
|
||||
this(new ArrayList<StatisticsStream>(), new StatisticsStream(), binWidth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new copy of the given histogram.
|
||||
* @param other - the histogram to copy.
|
||||
*/
|
||||
public HistogramStream(HistogramStream other) {
|
||||
// Deep cloning
|
||||
for (StatisticsStream stream : other.bins) {
|
||||
StatisticsStream copy = stream.copy();
|
||||
|
||||
// Update current
|
||||
if (stream == other.current)
|
||||
this.current = copy;
|
||||
this.bins.add(copy);
|
||||
}
|
||||
this.binWidth = other.binWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new histogram stream.
|
||||
* @param bins - list of bins.
|
||||
* @param current - the current selected bin. This will be added to the list if it is not already present.
|
||||
* @param binWidth - the desired number of observations in each bin.
|
||||
*/
|
||||
protected HistogramStream(List<StatisticsStream> bins, StatisticsStream current, int binWidth) {
|
||||
if (binWidth < 1)
|
||||
throw new IllegalArgumentException("binWidth cannot be less than 1");
|
||||
this.bins = Preconditions.checkNotNull(bins, "bins cannot be NULL");
|
||||
this.current = Preconditions.checkNotNull(current, "current cannot be NULL");
|
||||
this.binWidth = binWidth;
|
||||
|
||||
if (!this.bins.contains(current)) {
|
||||
this.bins.add(current);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public HistogramStream copy() {
|
||||
return new HistogramStream(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an immutable view of every bin in the histogram.
|
||||
* @return Every bin in the histogram.
|
||||
*/
|
||||
public ImmutableList<StatisticsStream> getBins() {
|
||||
return ImmutableList.copyOf(bins);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void observe(double value) {
|
||||
checkOverflow();
|
||||
count++;
|
||||
current.observe(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* See if the current bin has overflowed. If so, construct a new bin and set it as the current.
|
||||
*/
|
||||
protected void checkOverflow() {
|
||||
if (current.getCount() >= binWidth) {
|
||||
bins.add(current = new StatisticsStream());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the total statistics of every bin in the histogram.
|
||||
* <p>
|
||||
* This method is not thread safe.
|
||||
* @return The total statistics.
|
||||
*/
|
||||
public StatisticsStream getTotal() {
|
||||
StatisticsStream sum = null;
|
||||
|
||||
for (StatisticsStream stream : bins) {
|
||||
sum = sum != null ? stream.add(sum) : stream;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package com.comphenix.protocol.timing;
|
||||
|
||||
/**
|
||||
* Represents an online computation.
|
||||
* @author Kristian
|
||||
*/
|
||||
public abstract class OnlineComputation {
|
||||
/**
|
||||
* Retrieve the number of observations.
|
||||
* @return Number of observations.
|
||||
*/
|
||||
public abstract int getCount();
|
||||
|
||||
/**
|
||||
* Observe a value.
|
||||
* @param value - the observed value.
|
||||
*/
|
||||
public abstract void observe(double value);
|
||||
|
||||
/**
|
||||
* Construct a copy of the current online computation.
|
||||
* @return The new copy.
|
||||
*/
|
||||
public abstract OnlineComputation copy();
|
||||
|
||||
/**
|
||||
* Retrieve a wrapper for another online computation that is synchronized.
|
||||
* @param computation - the computation.
|
||||
* @return The synchronized wrapper.
|
||||
*/
|
||||
public static OnlineComputation synchronizedComputation(final OnlineComputation computation) {
|
||||
return new OnlineComputation() {
|
||||
@Override
|
||||
public synchronized void observe(double value) {
|
||||
computation.observe(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getCount() {
|
||||
return computation.getCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized OnlineComputation copy() {
|
||||
return computation.copy();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ package com.comphenix.protocol.timing;
|
||||
* Represents an online algortihm for computing the mean and standard deviation without storing every value.
|
||||
* @author Kristian
|
||||
*/
|
||||
public class StatisticsStream {
|
||||
public class StatisticsStream extends OnlineComputation {
|
||||
// This algorithm is due to Donald Knuth, as described in:
|
||||
// Donald E. Knuth (1998). The Art of Computer Programming, volume 2:
|
||||
// Seminumerical Algorithms, 3rd edn., p. 232. Boston: Addison-Wesley.
|
||||
@ -35,11 +35,17 @@ public class StatisticsStream {
|
||||
this.maximum = other.maximum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatisticsStream copy() {
|
||||
return new StatisticsStream(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Observe a value.
|
||||
* @param value - the observed value.
|
||||
*/
|
||||
public void observe(double value) {
|
||||
@Override
|
||||
public void observe(double value) {
|
||||
double delta = value - mean;
|
||||
|
||||
// As per Knuth
|
||||
@ -125,7 +131,8 @@ public class StatisticsStream {
|
||||
* Retrieve the number of observations.
|
||||
* @return Number of observations.
|
||||
*/
|
||||
public int getCount() {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return count;
|
||||
}
|
||||
|
||||
@ -134,4 +141,14 @@ public class StatisticsStream {
|
||||
throw new IllegalStateException("No observations in stream.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (count == 0)
|
||||
return "StatisticsStream [Nothing recorded]";
|
||||
|
||||
return String.format("StatisticsStream [Average: %.3f, SD: %.3f, Min: %.3f, Max: %.3f, Count: %s]",
|
||||
getMean(), getStandardDeviation(),
|
||||
getMinimum(), getMaximum(), getCount());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user