/
ShortCountsHistogram.java
261 lines (226 loc) · 10.8 KB
/
ShortCountsHistogram.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/**
* Written by Gil Tene of Azul Systems, and released to the public domain,
* as explained at http://creativecommons.org/publicdomain/zero/1.0/
*
* @author Gil Tene
*/
package org.HdrHistogram;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.zip.DataFormatException;
/**
* <h2>A High Dynamic Range (HDR) Histogram using a <b><code>short</code></b> count type </h2>
* <p>
* See package description for {@link org.HdrHistogram} for details.
*/
public class ShortCountsHistogram extends AbstractHistogram {
long totalCount;
short[] counts;
int normalizingIndexOffset;
@Override
long getCountAtIndex(final int index) {
return counts[normalizeIndex(index, normalizingIndexOffset, countsArrayLength)];
}
@Override
long getCountAtNormalizedIndex(final int index) {
return counts[index];
}
@Override
void incrementCountAtIndex(final int index) {
int normalizedIndex = normalizeIndex(index, normalizingIndexOffset, countsArrayLength);
short currentCount = counts[normalizedIndex];
short newCount = (short) (currentCount + 1);
if (newCount < 0) {
throw new IllegalStateException("would overflow short integer count");
}
counts[normalizedIndex] = newCount;
}
@Override
void addToCountAtIndex(final int index, final long value) {
int normalizedIndex = normalizeIndex(index, normalizingIndexOffset, countsArrayLength);
long currentCount = counts[normalizedIndex];
long newCount = (currentCount + value);
if ((newCount < Short.MIN_VALUE) || (newCount > Short.MAX_VALUE)) {
throw new IllegalStateException("would overflow short integer count");
}
counts[normalizedIndex] = (short) newCount;
}
@Override
void setCountAtIndex(int index, long value) {
setCountAtNormalizedIndex(normalizeIndex(index, normalizingIndexOffset, countsArrayLength), value);
}
@Override
void setCountAtNormalizedIndex(int index, long value) {
if ((value < 0) || (value > Short.MAX_VALUE)) {
throw new IllegalStateException("would overflow short integer count");
}
counts[index] = (short) value;
}
@Override
int getNormalizingIndexOffset() {
return normalizingIndexOffset;
}
@Override
void setNormalizingIndexOffset(int normalizingIndexOffset) {
this.normalizingIndexOffset = normalizingIndexOffset;
}
@Override
void setIntegerToDoubleValueConversionRatio(double integerToDoubleValueConversionRatio) {
nonConcurrentSetIntegerToDoubleValueConversionRatio(integerToDoubleValueConversionRatio);
}
@Override
void shiftNormalizingIndexByOffset(int offsetToAdd,
boolean lowestHalfBucketPopulated,
double newIntegerToDoubleValueConversionRatio) {
nonConcurrentNormalizingIndexShift(offsetToAdd, lowestHalfBucketPopulated);
}
@Override
void clearCounts() {
java.util.Arrays.fill(counts, (short) 0);
totalCount = 0;
}
@Override public ShortCountsHistogram copy() {
ShortCountsHistogram copy = new ShortCountsHistogram(this);
copy.add(this);
return copy;
}
@Override
public ShortCountsHistogram copyCorrectedForCoordinatedOmission(final long expectedIntervalBetweenValueSamples) {
ShortCountsHistogram toHistogram = new ShortCountsHistogram(this);
toHistogram.addWhileCorrectingForCoordinatedOmission(this, expectedIntervalBetweenValueSamples);
return toHistogram;
}
@Override
public long getTotalCount() {
return totalCount;
}
@Override
void setTotalCount(final long totalCount) {
this.totalCount = totalCount;
}
@Override
void incrementTotalCount() {
totalCount++;
}
@Override
void addToTotalCount(long value) {
totalCount += value;
}
@Override
int _getEstimatedFootprintInBytes() {
return (512 + (2 * counts.length));
}
@Override
void resize(long newHighestTrackableValue) {
int oldNormalizedZeroIndex = normalizeIndex(0, normalizingIndexOffset, countsArrayLength);
establishSize(newHighestTrackableValue);
int countsDelta = countsArrayLength - counts.length;
counts = Arrays.copyOf(counts, countsArrayLength);
if (oldNormalizedZeroIndex != 0) {
// We need to shift the stuff from the zero index and up to the end of the array:
int newNormalizedZeroIndex = oldNormalizedZeroIndex + countsDelta;
int lengthToCopy = (countsArrayLength - countsDelta) - oldNormalizedZeroIndex;
System.arraycopy(counts, oldNormalizedZeroIndex, counts, newNormalizedZeroIndex, lengthToCopy);
Arrays.fill(counts, oldNormalizedZeroIndex, newNormalizedZeroIndex, (short) 0);
}
}
/**
* Construct an auto-resizing ShortCountsHistogram with a lowest discernible value of 1 and an auto-adjusting
* highestTrackableValue. Can auto-resize up to track values up to (Long.MAX_VALUE / 2).
*
* @param numberOfSignificantValueDigits Specifies the precision to use. This is the number of significant
* decimal digits to which the histogram will maintain value resolution
* and separation. Must be a non-negative integer between 0 and 5.
*/
public ShortCountsHistogram(final int numberOfSignificantValueDigits) {
this(1, 2, numberOfSignificantValueDigits);
setAutoResize(true);
}
/**
* Construct a ShortCountsHistogram given the Highest value to be tracked and a number of significant decimal
* digits. The histogram will be constructed to implicitly track (distinguish from 0) values as low as 1.
*
* @param highestTrackableValue The highest value to be tracked by the histogram. Must be a positive
* integer that is {@literal >=} 2.
* @param numberOfSignificantValueDigits Specifies the precision to use. This is the number of significant
* decimal digits to which the histogram will maintain value resolution
* and separation. Must be a non-negative integer between 0 and 5.
*/
public ShortCountsHistogram(final long highestTrackableValue, final int numberOfSignificantValueDigits) {
this(1, highestTrackableValue, numberOfSignificantValueDigits);
}
/**
* Construct a ShortCountsHistogram given the Lowest and Highest values to be tracked and a number of significant
* decimal digits. Providing a lowestDiscernibleValue is useful is situations where the units used
* for the histogram's values are much smaller that the minimal accuracy required. E.g. when tracking
* time values stated in nanosecond units, where the minimal accuracy required is a microsecond, the
* proper value for lowestDiscernibleValue would be 1000.
*
* @param lowestDiscernibleValue The lowest value that can be tracked (distinguished from 0) by the histogram.
* Must be a positive integer that is {@literal >=} 1. May be internally rounded
* down to nearest power of 2.
* @param highestTrackableValue The highest value to be tracked by the histogram. Must be a positive
* integer that is {@literal >=} (2 * lowestDiscernibleValue).
* @param numberOfSignificantValueDigits Specifies the precision to use. This is the number of significant
* decimal digits to which the histogram will maintain value resolution
* and separation. Must be a non-negative integer between 0 and 5.
*/
public ShortCountsHistogram(final long lowestDiscernibleValue, final long highestTrackableValue,
final int numberOfSignificantValueDigits) {
super(lowestDiscernibleValue, highestTrackableValue, numberOfSignificantValueDigits);
counts = new short[countsArrayLength];
wordSizeInBytes = 2;
}
/**
* Construct a histogram with the same range settings as a given source histogram,
* duplicating the source's start/end timestamps (but NOT it's contents)
* @param source The source histogram to duplicate
*/
public ShortCountsHistogram(final AbstractHistogram source) {
super(source);
counts = new short[countsArrayLength];
wordSizeInBytes = 2;
}
/**
* Construct a new histogram by decoding it from a ByteBuffer.
* @param buffer The buffer to decode from
* @param minBarForHighestTrackableValue Force highestTrackableValue to be set at least this high
* @return The newly constructed histogram
*/
public static ShortCountsHistogram decodeFromByteBuffer(final ByteBuffer buffer,
final long minBarForHighestTrackableValue) {
return decodeFromByteBuffer(buffer, ShortCountsHistogram.class, minBarForHighestTrackableValue);
}
/**
* Construct a new histogram by decoding it from a compressed form in a ByteBuffer.
* @param buffer The buffer to decode from
* @param minBarForHighestTrackableValue Force highestTrackableValue to be set at least this high
* @return The newly constructed histogram
* @throws DataFormatException on error parsing/decompressing the buffer
*/
public static ShortCountsHistogram decodeFromCompressedByteBuffer(final ByteBuffer buffer,
final long minBarForHighestTrackableValue)
throws DataFormatException {
return decodeFromCompressedByteBuffer(buffer, ShortCountsHistogram.class, minBarForHighestTrackableValue);
}
/**
* Construct a new ShortCountsHistogram by decoding it from a String containing a base64 encoded
* compressed histogram representation.
*
* @param base64CompressedHistogramString A string containing a base64 encoding of a compressed histogram
* @return A ShortCountsHistogram decoded from the string
* @throws DataFormatException on error parsing/decompressing the input
*/
public static ShortCountsHistogram fromString(final String base64CompressedHistogramString)
throws DataFormatException {
return decodeFromCompressedByteBuffer(
ByteBuffer.wrap(Base64Helper.parseBase64Binary(base64CompressedHistogramString)),
0);
}
private void readObject(final ObjectInputStream o)
throws IOException, ClassNotFoundException {
o.defaultReadObject();
}
}