Adding interfaces in documentation
[aai/sparky-be.git] / sparkybe-onap-service / src / main / java / org / onap / aai / sparky / analytics / HistogramSampler.java
1 /**
2  * ============LICENSE_START===================================================
3  * SPARKY (AAI UI service)
4  * ============================================================================
5  * Copyright © 2017 AT&T Intellectual Property.
6  * Copyright © 2017 Amdocs
7  * All rights reserved.
8  * ============================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=====================================================
21  *
22  * ECOMP and OpenECOMP are trademarks
23  * and service marks of AT&T Intellectual Property.
24  */
25 package org.onap.aai.sparky.analytics;
26
27 /**
28  * A class that models a histogram for reporting and tracking long values with variable steps, bins,
29  * and floating point accuracy.
30  * 
31  * @author davea.
32  */
33 public final class HistogramSampler {
34
35   private String label;
36
37   private long binMaxValue;
38
39   private int numBins;
40
41   private double stepSize;
42
43   private long sampleValueTotal;
44
45   private long minValue = -1;
46
47   private long maxValue = 0;
48
49   private long numSamples = 0;
50
51   private long decimalPointAccuracy = 0;
52
53   private static String FORMAT_FLOAT_TEMPLATE = "%%.%df";
54
55   private String floatFormatStr;
56
57   private long[] histogramBins;
58
59   /**
60    * Instantiates a new histogram sampler.
61    *
62    * @param label the label
63    * @param maxValue the max value
64    * @param numBins the num bins
65    * @param decimalPointAccuracy the decimal point accuracy
66    */
67   public HistogramSampler(String label, long maxValue, int numBins, int decimalPointAccuracy) {
68     this.label = label;
69     this.binMaxValue = maxValue;
70     this.numBins = numBins;
71     this.stepSize = ((double) binMaxValue / (double) numBins);
72     this.decimalPointAccuracy = decimalPointAccuracy;
73     this.floatFormatStr = String.format(FORMAT_FLOAT_TEMPLATE, this.decimalPointAccuracy);
74
75     /*
76      * [numBins + 1] => last bin is catch-all for outliers
77      */
78
79     initializeHistogramBins(numBins + 1);
80
81   }
82
83   /**
84    * Initialize histogram bins.
85    *
86    * @param numBins the num bins
87    */
88   private void initializeHistogramBins(int numBins) {
89
90     histogramBins = new long[numBins];
91     int counter = 0;
92     while (counter < numBins) {
93       histogramBins[counter] = 0;
94       counter++;
95     }
96
97   }
98
99   /*
100    * Is it really necessary to synchronize the collection, or should we simply switch the underlying
101    * data type to an AtomicLong
102    */
103
104   /**
105    * Track.
106    *
107    * @param value the value
108    */
109   public synchronized void track(long value) {
110
111     if (value < 0) {
112       return;
113     }
114
115     sampleValueTotal += value;
116     numSamples++;
117
118     if (minValue == -1) {
119       minValue = value;
120     }
121
122     if (value < minValue) {
123       minValue = value;
124     }
125
126     if (value > maxValue) {
127       maxValue = value;
128     }
129
130     /*
131      * One step bin determination
132      */
133
134     if (value < (numBins * stepSize)) {
135
136       int index = (int) (value / stepSize);
137       histogramBins[index]++;
138
139     } else {
140       // peg the metric in the outlier bin
141       histogramBins[numBins - 1]++;
142     }
143
144   }
145
146   /**
147    * Clear.
148    */
149   public void clear() {
150
151     int counter = 0;
152     while (counter < numBins) {
153       histogramBins[counter] = 0;
154       counter++;
155     }
156
157     minValue = -1;
158     maxValue = 0;
159     numSamples = 0;
160     sampleValueTotal = 0;
161
162   }
163
164   /**
165    * Re initialize bins.
166    *
167    * @param label the label
168    * @param numBins the num bins
169    * @param maxValue the max value
170    * @param decimalPointAccuracy the decimal point accuracy
171    */
172   public void reInitializeBins(String label, int numBins, long maxValue, int decimalPointAccuracy) {
173     this.label = label;
174     this.decimalPointAccuracy = decimalPointAccuracy;
175     this.floatFormatStr = String.format(FORMAT_FLOAT_TEMPLATE, this.decimalPointAccuracy);
176     this.numBins = numBins;
177     this.minValue = -1;
178     this.maxValue = 0;
179     initializeHistogramBins(numBins);
180     this.stepSize = (maxValue / numBins);
181     clear();
182   }
183
184   public long getNumberOfSamples() {
185     return numSamples;
186   }
187
188   public long getTotalValueSum() {
189     return sampleValueTotal;
190   }
191
192   /**
193    * Gets the stats.
194    *
195    * @param formatted the formatted
196    * @param indentPadding the indent padding
197    * @return the stats
198    */
199   public String getStats(boolean formatted, String indentPadding) {
200
201     StringBuilder sb = new StringBuilder(128);
202
203
204     if (!formatted) {
205       // generate CSV in the following format
206
207       /*
208        * label,minValue,maxValue,avgValue,numSamples,stepSize,numSteps,stepCounters
209        */
210       sb.append(indentPadding);
211       sb.append(label).append(",");
212       sb.append(minValue).append(",");
213       sb.append(maxValue).append(",");
214       if (numSamples == 0) {
215         sb.append(0).append(",");
216       } else {
217         sb.append((sampleValueTotal / numSamples)).append(",");
218       }
219       sb.append(numSamples).append(",");
220       sb.append(numBins).append(",");
221       sb.append(String.format(floatFormatStr, stepSize));
222
223       int counter = 0;
224       while (counter < numBins) {
225
226         if (counter != (numBins)) {
227           sb.append(",");
228         }
229
230         sb.append(histogramBins[counter]);
231
232         counter++;
233
234       }
235
236       return sb.toString();
237
238     }
239
240     sb.append("\n");
241     sb.append(indentPadding).append("Label = ").append(label).append("\n");
242     sb.append(indentPadding).append("Min = ").append(minValue).append("\n");
243     sb.append(indentPadding).append("Max = ").append(maxValue).append("\n");
244     sb.append(indentPadding).append("numSamples = ").append(numSamples).append("\n");
245
246     if (numSamples == 0) {
247       sb.append(indentPadding).append("Avg = ").append(0).append("\n");
248     } else {
249       sb.append(indentPadding).append("Avg = ").append((sampleValueTotal / numSamples))
250           .append("\n");
251     }
252
253     sb.append(indentPadding).append("StepSize = ").append(String.format(floatFormatStr, stepSize))
254         .append("\n");
255
256     sb.append(indentPadding).append("Sample Histogram:").append("\n");
257
258     int counter = 0;
259     while (counter < numBins) {
260
261       if (counter == (numBins - 1)) {
262         // outlier bin
263         double leftBound = (stepSize * counter);
264         sb.append(indentPadding).append("\t")
265             .append(" x >= " + String.format(floatFormatStr, leftBound) + " : " 
266                 + histogramBins[counter])
267             .append("\n");
268
269       } else {
270         double leftBound = (stepSize * counter);
271         double rightBound = ((stepSize) * (counter + 1));
272         sb.append(indentPadding).append("\t")
273             .append((String.format(floatFormatStr, leftBound) + " < x < "
274                 + String.format(floatFormatStr, rightBound) + " : " + histogramBins[counter]))
275             .append("\n");
276       }
277
278       counter++;
279
280     }
281
282     return sb.toString();
283
284   }
285
286 }