@@ -331,21 +331,37 @@ func (h *Histogram) ValueAtPercentile(percentile float64) int64 {
331331 percentile = 100
332332 }
333333
334- total := int64 (0 )
335334 countAtPercentile := int64 (((percentile / 100 ) * float64 (h .totalCount )) + 0.5 )
335+ valueFromIdx := h .getValueFromIdxUpToCount (countAtPercentile )
336+ if percentile == 0.0 {
337+ return h .lowestEquivalentValue (valueFromIdx )
338+ }
339+ return h .highestEquivalentValue (valueFromIdx )
340+ }
336341
337- i := h .iterator ()
338- for i .nextCountAtIdx () {
339- total += i .countAtIdx
340- if total >= countAtPercentile {
341- if percentile == 0.0 {
342- return h .lowestEquivalentValue (i .valueFromIdx )
343- }
344- return h .highestEquivalentValue (i .valueFromIdx )
342+ func (h * Histogram ) getValueFromIdxUpToCount (countAtPercentile int64 ) int64 {
343+ var countToIdx int64
344+ var valueFromIdx int64
345+ var subBucketIdx int32 = - 1
346+ var bucketIdx int32
347+ bucketBaseIdx := h .getBucketBaseIdx (bucketIdx )
348+
349+ for {
350+ if countToIdx >= countAtPercentile {
351+ break
352+ }
353+ // increment bucket
354+ subBucketIdx ++
355+ if subBucketIdx >= h .subBucketCount {
356+ subBucketIdx = h .subBucketHalfCount
357+ bucketIdx ++
358+ bucketBaseIdx = h .getBucketBaseIdx (bucketIdx )
345359 }
346- }
347360
348- return 0
361+ countToIdx += h .getCountAtIndexGivenBucketBaseIdx (bucketBaseIdx , subBucketIdx )
362+ valueFromIdx = int64 (subBucketIdx ) << uint (int64 (bucketIdx )+ h .unitMagnitude )
363+ }
364+ return valueFromIdx
349365}
350366
351367// ValueAtPercentiles, given an slice of percentiles returns a map containing for each passed percentile,
@@ -372,7 +388,7 @@ func (h *Histogram) ValueAtPercentiles(percentiles []float64) (values map[float6
372388 total := int64 (0 )
373389 currentQuantileSlicePos := 0
374390 i := h .iterator ()
375- for currentQuantileSlicePos < totalQuantilesToCalculate && i .nextCountAtIdx () {
391+ for currentQuantileSlicePos < totalQuantilesToCalculate && i .nextCountAtIdx (h . totalCount ) {
376392 total += i .countAtIdx
377393 for currentQuantileSlicePos < totalQuantilesToCalculate && total >= countAtPercentiles [currentQuantileSlicePos ] {
378394 currentPercentile := percentiles [currentQuantileSlicePos ]
@@ -579,10 +595,16 @@ func (h *Histogram) getCountAtIndex(bucketIdx, subBucketIdx int32) int64 {
579595 return h .counts [h .countsIndex (bucketIdx , subBucketIdx )]
580596}
581597
598+ func (h * Histogram ) getCountAtIndexGivenBucketBaseIdx (bucketBaseIdx , subBucketIdx int32 ) int64 {
599+ return h .counts [bucketBaseIdx + subBucketIdx - h .subBucketHalfCount ]
600+ }
601+
582602func (h * Histogram ) countsIndex (bucketIdx , subBucketIdx int32 ) int32 {
583- bucketBaseIdx := (bucketIdx + 1 ) << uint (h .subBucketHalfCountMagnitude )
584- offsetInBucket := subBucketIdx - h .subBucketHalfCount
585- return bucketBaseIdx + offsetInBucket
603+ return h .getBucketBaseIdx (bucketIdx ) + subBucketIdx - h .subBucketHalfCount
604+ }
605+
606+ func (h * Histogram ) getBucketBaseIdx (bucketIdx int32 ) int32 {
607+ return (bucketIdx + 1 ) << uint (h .subBucketHalfCountMagnitude )
586608}
587609
588610// return the lowest (and therefore highest precision) bucket index that can represent the value
@@ -622,8 +644,8 @@ type iterator struct {
622644}
623645
624646// nextCountAtIdx does not update the iterator highestEquivalentValue in order to optimize cpu usage.
625- func (i * iterator ) nextCountAtIdx () bool {
626- if i .countToIdx >= i . h . totalCount {
647+ func (i * iterator ) nextCountAtIdx (limit int64 ) bool {
648+ if i .countToIdx >= limit {
627649 return false
628650 }
629651 // increment bucket
@@ -645,7 +667,7 @@ func (i *iterator) nextCountAtIdx() bool {
645667
646668// Returns the next element in the iteration.
647669func (i * iterator ) next () bool {
648- if ! i .nextCountAtIdx () {
670+ if ! i .nextCountAtIdx (i . h . totalCount ) {
649671 return false
650672 }
651673 i .highestEquivalentValue = i .h .highestEquivalentValue (i .valueFromIdx )
0 commit comments