2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 * Copyright © 2017 Amdocs
7 * ================================================================================
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 * ============LICENSE_END=========================================================
21 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
23 package org.onap.aai.sparky.analytics;
26 * A class that models a histogram for reporting and tracking long values with variable steps, bins,
27 * and floating point accuracy.
31 public final class HistogramSampler {
35 private long binMaxValue;
39 private double stepSize;
41 private long sampleValueTotal;
43 private long minValue = -1;
45 private long maxValue = 0;
47 private long numSamples = 0;
49 private long decimalPointAccuracy = 0;
51 private static String FORMAT_FLOAT_TEMPLATE = "%%.%df";
53 private String floatFormatStr;
55 private long[] histogramBins;
58 * Instantiates a new histogram sampler.
60 * @param label the label
61 * @param maxValue the max value
62 * @param numBins the num bins
63 * @param decimalPointAccuracy the decimal point accuracy
65 public HistogramSampler(String label, long maxValue, int numBins, int decimalPointAccuracy) {
67 this.binMaxValue = maxValue;
68 this.numBins = numBins;
69 this.stepSize = ((double) binMaxValue / (double) numBins);
70 this.decimalPointAccuracy = decimalPointAccuracy;
71 this.floatFormatStr = String.format(FORMAT_FLOAT_TEMPLATE, this.decimalPointAccuracy);
74 * [numBins + 1] => last bin is catch-all for outliers
77 initializeHistogramBins(numBins + 1);
82 * Initialize histogram bins.
84 * @param numBins the num bins
86 private void initializeHistogramBins(int numBins) {
88 histogramBins = new long[numBins];
90 while (counter < numBins) {
91 histogramBins[counter] = 0;
98 * Is it really necessary to synchronize the collection, or should we simply switch the underlying
99 * data type to an AtomicLong
105 * @param value the value
107 public synchronized void track(long value) {
113 sampleValueTotal += value;
116 if (minValue == -1) {
120 if (value < minValue) {
124 if (value > maxValue) {
129 * One step bin determination
132 if (value < (numBins * stepSize)) {
134 int index = (int) (value / stepSize);
135 histogramBins[index]++;
138 // peg the metric in the outlier bin
139 histogramBins[numBins - 1]++;
147 public void clear() {
150 while (counter < numBins) {
151 histogramBins[counter] = 0;
158 sampleValueTotal = 0;
163 * Re initialize bins.
165 * @param label the label
166 * @param numBins the num bins
167 * @param maxValue the max value
168 * @param decimalPointAccuracy the decimal point accuracy
170 public void reInitializeBins(String label, int numBins, long maxValue, int decimalPointAccuracy) {
172 this.decimalPointAccuracy = decimalPointAccuracy;
173 this.floatFormatStr = String.format(FORMAT_FLOAT_TEMPLATE, this.decimalPointAccuracy);
174 this.numBins = numBins;
177 initializeHistogramBins(numBins);
178 this.stepSize = (maxValue / numBins);
182 public long getNumberOfSamples() {
186 public long getTotalValueSum() {
187 return sampleValueTotal;
193 * @param formatted the formatted
194 * @param indentPadding the indent padding
197 public String getStats(boolean formatted, String indentPadding) {
199 StringBuilder sb = new StringBuilder(128);
203 // generate CSV in the following format
206 * label,minValue,maxValue,avgValue,numSamples,stepSize,numSteps,stepCounters
208 sb.append(indentPadding);
209 sb.append(label).append(",");
210 sb.append(minValue).append(",");
211 sb.append(maxValue).append(",");
212 if (numSamples == 0) {
213 sb.append(0).append(",");
215 sb.append((sampleValueTotal / numSamples)).append(",");
217 sb.append(numSamples).append(",");
218 sb.append(numBins).append(",");
219 sb.append(String.format(floatFormatStr, stepSize));
222 while (counter < numBins) {
224 if (counter != (numBins)) {
228 sb.append(histogramBins[counter]);
234 return sb.toString();
239 sb.append(indentPadding).append("Label = ").append(label).append("\n");
240 sb.append(indentPadding).append("Min = ").append(minValue).append("\n");
241 sb.append(indentPadding).append("Max = ").append(maxValue).append("\n");
242 sb.append(indentPadding).append("numSamples = ").append(numSamples).append("\n");
244 if (numSamples == 0) {
245 sb.append(indentPadding).append("Avg = ").append(0).append("\n");
247 sb.append(indentPadding).append("Avg = ").append((sampleValueTotal / numSamples))
251 sb.append(indentPadding).append("StepSize = ").append(String.format(floatFormatStr, stepSize))
254 sb.append(indentPadding).append("Sample Histogram:").append("\n");
257 while (counter < numBins) {
259 if (counter == (numBins - 1)) {
261 double leftBound = (stepSize * counter);
262 sb.append(indentPadding).append("\t")
263 .append(" x >= " + String.format(floatFormatStr, leftBound) + " : "
264 + histogramBins[counter])
268 double leftBound = (stepSize * counter);
269 double rightBound = ((stepSize) * (counter + 1));
270 sb.append(indentPadding).append("\t")
271 .append((String.format(floatFormatStr, leftBound) + " < x < "
272 + String.format(floatFormatStr, rightBound) + " : " + histogramBins[counter]))
280 return sb.toString();