// =================================================================================================
// Copyright 2011 Twitter, Inc.
// -------------------------------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this work except in compliance with the License.
// You may obtain a copy of the License in the LICENSE file, or at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// =================================================================================================
package com.twitter.common.stats;
import com.google.common.base.Preconditions;
public class PrintableHistogram {
private double[] bucketBoundaries;
private int[] bucketCounts;
private int totalCount = 0;
/**
* Creates a histogram with the given bucket boundaries. The boundaries
* 0 and infinity are implicitly added.
*
* @param buckets Boundaries for histogram buckets.
*/
public PrintableHistogram(double ... buckets) {
Preconditions.checkState(buckets[0] != 0);
bucketBoundaries = new double[buckets.length + 2];
bucketBoundaries[0] = 0;
bucketCounts = new int[buckets.length + 2];
for (int i = 0; i < buckets.length; i++) {
if (i > 0) {
Preconditions.checkState(buckets[i] > buckets[i - 1],
"Bucket %f must be greater than %f.", buckets[i], buckets[i - 1]);
}
bucketCounts[i] = 0;
bucketBoundaries[i + 1] = buckets[i];
}
bucketBoundaries[bucketBoundaries.length - 1] = Integer.MAX_VALUE;
}
public void addValue(double value) {
addValue(value, 1);
}
public void addValue(double value, int count) {
Preconditions.checkState(value >= 0);
Preconditions.checkState(count >= 0);
Preconditions.checkState(bucketBoundaries.length > 1);
int bucketId = -1;
for (double boundary : bucketBoundaries) {
if (value <= boundary) {
break;
}
bucketId++;
}
bucketId = Math.max(0, bucketId);
bucketId = Math.min(bucketCounts.length - 1, bucketId);
bucketCounts[bucketId] += count;
totalCount += count;
}
public double getBucketRatio(int bucketId) {
Preconditions.checkState(bucketId >= 0);
Preconditions.checkState(bucketId < bucketCounts.length);
return (double) bucketCounts[bucketId] / totalCount;
}
public String toString() {
StringBuilder display = new StringBuilder();
display.append("Histogram: ");
for (int bucketId = 0; bucketId < bucketCounts.length - 1; bucketId++) {
display.append(String.format("\n(%g - %g]\n\t",
bucketBoundaries[bucketId], bucketBoundaries[bucketId + 1]));
for (int i = 0; i < getBucketRatio(bucketId) * 100; i++) {
display.append('#');
}
display.append(
String.format(" %.2g%% (%d)", getBucketRatio(bucketId) * 100, bucketCounts[bucketId]));
}
return display.toString();
}
}