Initial commit for AAI-UI(sparky-backend)
[aai/sparky-be.git] / src / main / java / org / openecomp / 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
26 package org.openecomp.sparky.analytics;
27
28 /**
29  * A class that models a histogram for reporting and tracking long values with variable steps, bins,
30  * and floating point accuracy.
31  * 
32  * @author davea.
33  */
34 public final class HistogramSampler {
35
36   private String label;
37
38   private long binMaxValue;
39
40   private int numBins;
41
42   private double stepSize;
43
44   private long sampleValueTotal;
45
46   private long minValue = -1;
47
48   private long maxValue = 0;
49
50   private long numSamples = 0;
51
52   private long decimalPointAccuracy = 0;
53
54   private static String FORMAT_FLOAT_TEMPLATE = "%%.%df";
55
56   private String floatFormatStr;
57
58   private long[] histogramBins;
59
60   /**
61    * Instantiates a new histogram sampler.
62    *
63    * @param label the label
64    * @param maxValue the max value
65    * @param numBins the num bins
66    * @param decimalPointAccuracy the decimal point accuracy
67    */
68   public HistogramSampler(String label, long maxValue, int numBins, int decimalPointAccuracy) {
69     this.label = label;
70     this.binMaxValue = maxValue;
71     this.numBins = numBins;
72     this.stepSize = ((double) binMaxValue / (double) numBins);
73     this.decimalPointAccuracy = decimalPointAccuracy;
74     this.floatFormatStr = String.format(FORMAT_FLOAT_TEMPLATE, this.decimalPointAccuracy);
75
76     /*
77      * [numBins + 1] => last bin is catch-all for outliers
78      */
79
80     initializeHistogramBins(numBins + 1);
81
82   }
83
84   /**
85    * Initialize histogram bins.
86    *
87    * @param numBins the num bins
88    */
89   private void initializeHistogramBins(int numBins) {
90
91     histogramBins = new long[numBins];
92     int counter = 0;
93     while (counter < numBins) {
94       histogramBins[counter] = 0;
95       counter++;
96     }
97
98   }
99
100   /*
101    * Is it really necessary to synchronize the collection, or should we simply switch the underlying
102    * data type to an AtomicLong
103    */
104
105   /**
106    * Track.
107    *
108    * @param value the value
109    */
110   public synchronized void track(long value) {
111
112     if (value < 0) {
113       return;
114     }
115
116     sampleValueTotal += value;
117     numSamples++;
118
119     if (minValue == -1) {
120       minValue = value;
121     }
122
123     if (value < minValue) {
124       minValue = value;
125     }
126
127     if (value > maxValue) {
128       maxValue = value;
129     }
130
131     /*
132      * One step bin determination
133      */
134
135     if (value < (numBins * stepSize)) {
136
137       int index = (int) (value / stepSize);
138       histogramBins[index]++;
139
140     } else {
141       // peg the metric in the outlier bin
142       histogramBins[numBins - 1]++;
143     }
144
145   }
146
147   /**
148    * Clear.
149    */
150   public void clear() {
151
152     int counter = 0;
153     while (counter < numBins) {
154       histogramBins[counter] = 0;
155       counter++;
156     }
157
158     minValue = -1;
159     maxValue = 0;
160     numSamples = 0;
161     sampleValueTotal = 0;
162
163   }
164
165   /**
166    * Re initialize bins.
167    *
168    * @param label the label
169    * @param numBins the num bins
170    * @param maxValue the max value
171    * @param decimalPointAccuracy the decimal point accuracy
172    */
173   public void reInitializeBins(String label, int numBins, long maxValue, int decimalPointAccuracy) {
174     this.label = label;
175     this.decimalPointAccuracy = decimalPointAccuracy;
176     this.floatFormatStr = String.format(FORMAT_FLOAT_TEMPLATE, this.decimalPointAccuracy);
177     this.numBins = numBins;
178     this.minValue = -1;
179     this.maxValue = 0;
180     initializeHistogramBins(numBins);
181     this.stepSize = (maxValue / numBins);
182     clear();
183   }
184
185   public long getNumberOfSamples() {
186     return numSamples;
187   }
188
189   public long getTotalValueSum() {
190     return sampleValueTotal;
191   }
192
193   /**
194    * Gets the stats.
195    *
196    * @param formatted the formatted
197    * @param indentPadding the indent padding
198    * @return the stats
199    */
200   public String getStats(boolean formatted, String indentPadding) {
201
202     StringBuilder sb = new StringBuilder(128);
203
204
205     if (!formatted) {
206       // generate CSV in the following format
207
208       /*
209        * label,minValue,maxValue,avgValue,numSamples,stepSize,numSteps,stepCounters
210        */
211       sb.append(indentPadding);
212       sb.append(label).append(",");
213       sb.append(minValue).append(",");
214       sb.append(maxValue).append(",");
215       if (numSamples == 0) {
216         sb.append(0).append(",");
217       } else {
218         sb.append((sampleValueTotal / numSamples)).append(",");
219       }
220       sb.append(numSamples).append(",");
221       sb.append(numBins).append(",");
222       sb.append(String.format(floatFormatStr, stepSize));
223
224       int counter = 0;
225       while (counter < numBins) {
226
227         if (counter != (numBins)) {
228           sb.append(",");
229         }
230
231         sb.append(histogramBins[counter]);
232
233         counter++;
234
235       }
236
237       return sb.toString();
238
239     }
240
241     sb.append("\n");
242     sb.append(indentPadding).append("Label = ").append(label).append("\n");
243     sb.append(indentPadding).append("Min = ").append(minValue).append("\n");
244     sb.append(indentPadding).append("Max = ").append(maxValue).append("\n");
245     sb.append(indentPadding).append("numSamples = ").append(numSamples).append("\n");
246
247     if (numSamples == 0) {
248       sb.append(indentPadding).append("Avg = ").append(0).append("\n");
249     } else {
250       sb.append(indentPadding).append("Avg = ").append((sampleValueTotal / numSamples))
251           .append("\n");
252     }
253
254     sb.append(indentPadding).append("StepSize = ").append(String.format(floatFormatStr, stepSize))
255         .append("\n");
256
257     sb.append(indentPadding).append("Sample Histogram:").append("\n");
258
259     int counter = 0;
260     while (counter < numBins) {
261
262       if (counter == (numBins - 1)) {
263         // outlier bin
264         double leftBound = (stepSize * counter);
265         sb.append(indentPadding).append("\t")
266             .append(" x >= " + String.format(floatFormatStr, leftBound) + " : " 
267                 + histogramBins[counter])
268             .append("\n");
269
270       } else {
271         double leftBound = (stepSize * counter);
272         double rightBound = ((stepSize) * (counter + 1));
273         sb.append(indentPadding).append("\t")
274             .append((String.format(floatFormatStr, leftBound) + " < x < "
275                 + String.format(floatFormatStr, rightBound) + " : " + histogramBins[counter]))
276             .append("\n");
277       }
278
279       counter++;
280
281     }
282
283     return sb.toString();
284
285   }
286
287 }