@@ -27,14 +27,32 @@ class FixedBoundaryHistogram {
27
27
28
28
private final boolean isCumulativeBucketCounts ;
29
29
30
+ /**
31
+ * Creates a FixedBoundaryHistogram which tracks the count of values for each bucket
32
+ * bound).
33
+ * @param buckets - sorted bucket boundaries
34
+ * @param isCumulativeBucketCounts - whether the count values should be cumulative
35
+ * count of lower buckets and current bucket.
36
+ */
30
37
FixedBoundaryHistogram (double [] buckets , boolean isCumulativeBucketCounts ) {
31
38
this .buckets = buckets ;
32
39
this .values = new AtomicLongArray (buckets .length );
33
40
this .isCumulativeBucketCounts = isCumulativeBucketCounts ;
34
41
}
35
42
36
- long countAtValue (double value ) {
37
- int index = Arrays .binarySearch (buckets , value );
43
+ double [] getBuckets () {
44
+ return this .buckets ;
45
+ }
46
+
47
+ /**
48
+ * Returns the number of values that was recorded between previous bucket and the
49
+ * queried bucket (upper bound inclusive)
50
+ * @param bucket - the bucket to find values for
51
+ * @return 0 if bucket is not a valid bucket otherwise number of values recorded
52
+ * between (index(bucket) - 1, bucket]
53
+ */
54
+ private long countAtBucket (double bucket ) {
55
+ int index = Arrays .binarySearch (buckets , bucket );
38
56
if (index < 0 )
39
57
return 0 ;
40
58
return values .get (index );
@@ -53,18 +71,20 @@ void record(long value) {
53
71
}
54
72
55
73
/**
56
- * The least bucket that is less than or equal to a sample.
74
+ * The least bucket that is less than or equal to a valueToRecord. Returns -1, if the
75
+ * valueToRecord is greater than the highest bucket.
57
76
*/
58
- int leastLessThanOrEqualTo (double key ) {
77
+ // VisibleForTesting
78
+ int leastLessThanOrEqualTo (long valueToRecord ) {
59
79
int low = 0 ;
60
80
int high = buckets .length - 1 ;
61
81
62
82
while (low <= high ) {
63
83
int mid = (low + high ) >>> 1 ;
64
- double value = buckets [mid ];
65
- if (value < key )
84
+ double bucket = buckets [mid ];
85
+ if (bucket < valueToRecord )
66
86
low = mid + 1 ;
67
- else if (value > key )
87
+ else if (bucket > valueToRecord )
68
88
high = mid - 1 ;
69
89
else
70
90
return mid ; // exact match
@@ -73,28 +93,49 @@ else if (value > key)
73
93
return low < buckets .length ? low : -1 ;
74
94
}
75
95
76
- Iterator <CountAtBucket > countsAtValues (Iterator <Double > values ) {
96
+ Iterator <CountAtBucket > countsAtValues (Iterator <Double > buckets ) {
77
97
return new Iterator <CountAtBucket >() {
78
98
private double cumulativeCount = 0.0 ;
79
99
80
100
@ Override
81
101
public boolean hasNext () {
82
- return values .hasNext ();
102
+ return buckets .hasNext ();
83
103
}
84
104
85
105
@ Override
86
106
public CountAtBucket next () {
87
- double value = values .next ();
88
- double count = countAtValue ( value );
107
+ double bucket = buckets .next ();
108
+ double count = countAtBucket ( bucket );
89
109
if (isCumulativeBucketCounts ) {
90
110
cumulativeCount += count ;
91
- return new CountAtBucket (value , cumulativeCount );
111
+ return new CountAtBucket (bucket , cumulativeCount );
92
112
}
93
113
else {
94
- return new CountAtBucket (value , count );
114
+ return new CountAtBucket (bucket , count );
95
115
}
96
116
}
97
117
};
98
118
}
99
119
120
+ /**
121
+ * Returns the list of {@link CountAtBucket} for each of the buckets tracked by this
122
+ * histogram.
123
+ */
124
+ CountAtBucket [] getCountsAtBucket () {
125
+ CountAtBucket [] countAtBuckets = new CountAtBucket [this .buckets .length ];
126
+ long cumulativeCount = 0 ;
127
+
128
+ for (int i = 0 ; i < this .buckets .length ; i ++) {
129
+ final long valueAtCurrentBucket = values .get (i );
130
+ if (isCumulativeBucketCounts ) {
131
+ cumulativeCount += valueAtCurrentBucket ;
132
+ countAtBuckets [i ] = new CountAtBucket (buckets [i ], cumulativeCount );
133
+ }
134
+ else {
135
+ countAtBuckets [i ] = new CountAtBucket (buckets [i ], valueAtCurrentBucket );
136
+ }
137
+ }
138
+ return countAtBuckets ;
139
+ }
140
+
100
141
}
0 commit comments