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