2021-06-28 15:00:55 +00:00
|
|
|
// Copyright 2021 The Prometheus Authors
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package histogram
|
|
|
|
|
2021-07-03 17:34:34 +00:00
|
|
|
import (
|
2021-11-09 20:45:04 +00:00
|
|
|
"fmt"
|
2021-07-03 17:34:34 +00:00
|
|
|
"math"
|
2021-11-09 20:45:04 +00:00
|
|
|
"strings"
|
2023-10-09 13:09:46 +00:00
|
|
|
|
|
|
|
"golang.org/x/exp/slices"
|
2021-07-03 17:34:34 +00:00
|
|
|
)
|
2021-07-03 13:53:56 +00:00
|
|
|
|
2023-01-04 09:58:18 +00:00
|
|
|
// CounterResetHint contains the known information about a counter reset,
|
|
|
|
// or alternatively that we are dealing with a gauge histogram, where counter resets do not apply.
|
|
|
|
type CounterResetHint byte
|
|
|
|
|
|
|
|
const (
|
|
|
|
UnknownCounterReset CounterResetHint = iota // UnknownCounterReset means we cannot say if this histogram signals a counter reset or not.
|
|
|
|
CounterReset // CounterReset means there was definitely a counter reset starting from this histogram.
|
|
|
|
NotCounterReset // NotCounterReset means there was definitely no counter reset with this histogram.
|
|
|
|
GaugeType // GaugeType means this is a gauge histogram, where counter resets do not happen.
|
|
|
|
)
|
|
|
|
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
// Histogram encodes a sparse, high-resolution histogram. See the design
|
|
|
|
// document for full details:
|
|
|
|
// https://docs.google.com/document/d/1cLNv3aufPZb3fNfaJgdaRBZsInZKKIHo9E6HinJVbpM/edit#
|
2021-07-02 15:37:40 +00:00
|
|
|
//
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
// The most tricky bit is how bucket indices represent real bucket boundaries.
|
|
|
|
// An example for schema 0 (by which each bucket is twice as wide as the
|
|
|
|
// previous bucket):
|
2021-07-02 15:37:40 +00:00
|
|
|
//
|
histograms: Add Compact method to the normal integer Histogram
And use the new method to call to compact Histograms during
parsing. This happens for both `Histogram` and `FloatHistogram`. In
this way, if targets decide to optimize the exposition size by merging
spans with empty buckets in between, we still get a normalized
results. It will also normalize away any valid but weird
representations like empty spans, spans with offset zero, and empty
buckets at the start or end of a span.
The implementation seemed easy at first as it just turns the
`compactBuckets` helper into a generic function (which now got its own
file). However, the integer Histograms have delta buckets instead of
absolute buckets, which had to be treated specially in the generic
`compactBuckets` function. To make sure it works, I have added plenty
of explicit tests for `Histogram` in addition to the `FloatHistogram`
tests.
I have also updated the doc comment for the `Compact` method.
Based on the insights now expressed in the doc comment, compacting
with a maxEmptyBuckets > 0 is rarely useful. Therefore, this commit
also sets the value to 0 in the two cases we were using 3 so far. We
might still want to reconsider, so I don't want to remove the
maxEmptyBuckets parameter right now.
Signed-off-by: beorn7 <beorn@grafana.com>
2022-09-27 11:04:16 +00:00
|
|
|
// Bucket boundaries → [-2,-1) [-1,-0.5) [-0.5,-0.25) ... [-0.001,0.001] ... (0.25,0.5] (0.5,1] (1,2] ....
|
|
|
|
// ↑ ↑ ↑ ↑ ↑ ↑ ↑
|
|
|
|
// Zero bucket (width e.g. 0.001) → | | | ZB | | |
|
|
|
|
// Positive bucket indices → | | | ... -1 0 1 2 3
|
|
|
|
// Negative bucket indices → 3 2 1 0 -1 ...
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
//
|
2022-03-22 15:02:13 +00:00
|
|
|
// Which bucket indices are actually used is determined by the spans.
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
type Histogram struct {
|
2023-01-04 09:58:18 +00:00
|
|
|
// Counter reset information.
|
|
|
|
CounterResetHint CounterResetHint
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
// Currently valid schema numbers are -4 <= n <= 8. They are all for
|
|
|
|
// base-2 bucket schemas, where 1 is a bucket boundary in each case, and
|
|
|
|
// then each power of two is divided into 2^n logarithmic buckets. Or
|
|
|
|
// in other words, each bucket boundary is the previous boundary times
|
|
|
|
// 2^(2^-n).
|
|
|
|
Schema int32
|
|
|
|
// Width of the zero bucket.
|
|
|
|
ZeroThreshold float64
|
|
|
|
// Observations falling into the zero bucket.
|
|
|
|
ZeroCount uint64
|
|
|
|
// Total number of observations.
|
|
|
|
Count uint64
|
2021-11-15 20:49:25 +00:00
|
|
|
// Sum of observations. This is also used as the stale marker.
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
Sum float64
|
|
|
|
// Spans for positive and negative buckets (see Span below).
|
|
|
|
PositiveSpans, NegativeSpans []Span
|
|
|
|
// Observation counts in buckets. The first element is an absolute
|
|
|
|
// count. All following ones are deltas relative to the previous
|
|
|
|
// element.
|
2021-06-28 15:00:55 +00:00
|
|
|
PositiveBuckets, NegativeBuckets []int64
|
|
|
|
}
|
|
|
|
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
// A Span defines a continuous sequence of buckets.
|
2021-06-28 15:00:55 +00:00
|
|
|
type Span struct {
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
// Gap to previous span (always positive), or starting index for the 1st
|
|
|
|
// span (which can be negative).
|
2021-06-28 15:00:55 +00:00
|
|
|
Offset int32
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
// Length of the span.
|
2021-06-28 15:00:55 +00:00
|
|
|
Length uint32
|
|
|
|
}
|
2021-06-30 10:45:43 +00:00
|
|
|
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
// Copy returns a deep copy of the Histogram.
|
2021-11-23 18:40:49 +00:00
|
|
|
func (h *Histogram) Copy() *Histogram {
|
|
|
|
c := *h
|
2021-06-30 10:45:43 +00:00
|
|
|
|
2021-11-29 07:54:23 +00:00
|
|
|
if len(h.PositiveSpans) != 0 {
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
c.PositiveSpans = make([]Span, len(h.PositiveSpans))
|
|
|
|
copy(c.PositiveSpans, h.PositiveSpans)
|
2021-06-30 10:45:43 +00:00
|
|
|
}
|
2021-11-29 07:54:23 +00:00
|
|
|
if len(h.NegativeSpans) != 0 {
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
c.NegativeSpans = make([]Span, len(h.NegativeSpans))
|
|
|
|
copy(c.NegativeSpans, h.NegativeSpans)
|
2021-06-30 10:45:43 +00:00
|
|
|
}
|
2021-11-29 07:54:23 +00:00
|
|
|
if len(h.PositiveBuckets) != 0 {
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
c.PositiveBuckets = make([]int64, len(h.PositiveBuckets))
|
|
|
|
copy(c.PositiveBuckets, h.PositiveBuckets)
|
2021-06-30 10:45:43 +00:00
|
|
|
}
|
2021-11-29 07:54:23 +00:00
|
|
|
if len(h.NegativeBuckets) != 0 {
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
c.NegativeBuckets = make([]int64, len(h.NegativeBuckets))
|
|
|
|
copy(c.NegativeBuckets, h.NegativeBuckets)
|
2021-06-30 10:45:43 +00:00
|
|
|
}
|
|
|
|
|
2021-11-09 20:45:04 +00:00
|
|
|
return &c
|
|
|
|
}
|
|
|
|
|
|
|
|
// String returns a string representation of the Histogram.
|
2021-11-23 18:40:49 +00:00
|
|
|
func (h *Histogram) String() string {
|
2021-11-09 20:45:04 +00:00
|
|
|
var sb strings.Builder
|
|
|
|
fmt.Fprintf(&sb, "{count:%d, sum:%g", h.Count, h.Sum)
|
|
|
|
|
2022-10-03 11:15:27 +00:00
|
|
|
var nBuckets []Bucket[uint64]
|
2021-11-09 20:45:04 +00:00
|
|
|
for it := h.NegativeBucketIterator(); it.Next(); {
|
|
|
|
bucket := it.At()
|
|
|
|
if bucket.Count != 0 {
|
|
|
|
nBuckets = append(nBuckets, it.At())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for i := len(nBuckets) - 1; i >= 0; i-- {
|
|
|
|
fmt.Fprintf(&sb, ", %s", nBuckets[i].String())
|
|
|
|
}
|
|
|
|
|
|
|
|
if h.ZeroCount != 0 {
|
|
|
|
fmt.Fprintf(&sb, ", %s", h.ZeroBucket().String())
|
|
|
|
}
|
|
|
|
|
|
|
|
for it := h.PositiveBucketIterator(); it.Next(); {
|
|
|
|
bucket := it.At()
|
|
|
|
if bucket.Count != 0 {
|
|
|
|
fmt.Fprintf(&sb, ", %s", bucket.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sb.WriteRune('}')
|
|
|
|
return sb.String()
|
|
|
|
}
|
|
|
|
|
|
|
|
// ZeroBucket returns the zero bucket.
|
2022-10-03 11:15:27 +00:00
|
|
|
func (h *Histogram) ZeroBucket() Bucket[uint64] {
|
|
|
|
return Bucket[uint64]{
|
2021-11-09 20:45:04 +00:00
|
|
|
Lower: -h.ZeroThreshold,
|
|
|
|
Upper: h.ZeroThreshold,
|
|
|
|
LowerInclusive: true,
|
|
|
|
UpperInclusive: true,
|
|
|
|
Count: h.ZeroCount,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// PositiveBucketIterator returns a BucketIterator to iterate over all positive
|
|
|
|
// buckets in ascending order (starting next to the zero bucket and going up).
|
2022-10-03 11:15:27 +00:00
|
|
|
func (h *Histogram) PositiveBucketIterator() BucketIterator[uint64] {
|
2023-10-09 06:40:59 +00:00
|
|
|
it := newRegularBucketIterator(h.PositiveSpans, h.PositiveBuckets, h.Schema, true)
|
|
|
|
return &it
|
2021-11-09 20:45:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NegativeBucketIterator returns a BucketIterator to iterate over all negative
|
|
|
|
// buckets in descending order (starting next to the zero bucket and going down).
|
2022-10-03 11:15:27 +00:00
|
|
|
func (h *Histogram) NegativeBucketIterator() BucketIterator[uint64] {
|
2023-10-09 06:40:59 +00:00
|
|
|
it := newRegularBucketIterator(h.NegativeSpans, h.NegativeBuckets, h.Schema, false)
|
|
|
|
return &it
|
2021-06-30 10:45:43 +00:00
|
|
|
}
|
2021-07-03 13:53:56 +00:00
|
|
|
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
// CumulativeBucketIterator returns a BucketIterator to iterate over a
|
|
|
|
// cumulative view of the buckets. This method currently only supports
|
|
|
|
// Histograms without negative buckets and panics if the Histogram has negative
|
|
|
|
// buckets. It is currently only used for testing.
|
2022-10-03 11:15:27 +00:00
|
|
|
func (h *Histogram) CumulativeBucketIterator() BucketIterator[uint64] {
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
if len(h.NegativeBuckets) > 0 {
|
2021-11-23 18:40:49 +00:00
|
|
|
panic("CumulativeBucketIterator called on Histogram with negative buckets")
|
|
|
|
}
|
|
|
|
return &cumulativeBucketIterator{h: h, posSpansIdx: -1}
|
|
|
|
}
|
|
|
|
|
2022-09-19 07:40:30 +00:00
|
|
|
// Equals returns true if the given histogram matches exactly.
|
|
|
|
// Exact match is when there are no new buckets (even empty) and no missing buckets,
|
|
|
|
// and all the bucket values match. Spans can have different empty length spans in between,
|
|
|
|
// but they must represent the same bucket layout to match.
|
2023-10-09 13:09:46 +00:00
|
|
|
// Sum is compared based on its bit pattern because this method
|
|
|
|
// is about data equality rather than mathematical equality.
|
2022-09-19 07:40:30 +00:00
|
|
|
func (h *Histogram) Equals(h2 *Histogram) bool {
|
|
|
|
if h2 == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if h.Schema != h2.Schema || h.ZeroThreshold != h2.ZeroThreshold ||
|
2023-09-25 13:03:55 +00:00
|
|
|
h.ZeroCount != h2.ZeroCount || h.Count != h2.Count ||
|
|
|
|
math.Float64bits(h.Sum) != math.Float64bits(h2.Sum) {
|
2022-09-19 07:40:30 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if !spansMatch(h.PositiveSpans, h2.PositiveSpans) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if !spansMatch(h.NegativeSpans, h2.NegativeSpans) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2023-10-09 13:09:46 +00:00
|
|
|
if !slices.Equal(h.PositiveBuckets, h2.PositiveBuckets) {
|
2022-09-19 07:40:30 +00:00
|
|
|
return false
|
|
|
|
}
|
2023-10-09 13:09:46 +00:00
|
|
|
if !slices.Equal(h.NegativeBuckets, h2.NegativeBuckets) {
|
2022-09-19 07:40:30 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// spansMatch returns true if both spans represent the same bucket layout
|
|
|
|
// after combining zero length spans with the next non-zero length span.
|
|
|
|
func spansMatch(s1, s2 []Span) bool {
|
|
|
|
if len(s1) == 0 && len(s2) == 0 {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
s1idx, s2idx := 0, 0
|
|
|
|
for {
|
|
|
|
if s1idx >= len(s1) {
|
|
|
|
return allEmptySpans(s2[s2idx:])
|
|
|
|
}
|
|
|
|
if s2idx >= len(s2) {
|
|
|
|
return allEmptySpans(s1[s1idx:])
|
|
|
|
}
|
|
|
|
|
|
|
|
currS1, currS2 := s1[s1idx], s2[s2idx]
|
|
|
|
s1idx++
|
|
|
|
s2idx++
|
|
|
|
if currS1.Length == 0 {
|
|
|
|
// This span is zero length, so we add consecutive such spans
|
|
|
|
// until we find a non-zero span.
|
|
|
|
for ; s1idx < len(s1) && s1[s1idx].Length == 0; s1idx++ {
|
|
|
|
currS1.Offset += s1[s1idx].Offset
|
|
|
|
}
|
|
|
|
if s1idx < len(s1) {
|
|
|
|
currS1.Offset += s1[s1idx].Offset
|
|
|
|
currS1.Length = s1[s1idx].Length
|
|
|
|
s1idx++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if currS2.Length == 0 {
|
|
|
|
// This span is zero length, so we add consecutive such spans
|
|
|
|
// until we find a non-zero span.
|
|
|
|
for ; s2idx < len(s2) && s2[s2idx].Length == 0; s2idx++ {
|
|
|
|
currS2.Offset += s2[s2idx].Offset
|
|
|
|
}
|
|
|
|
if s2idx < len(s2) {
|
|
|
|
currS2.Offset += s2[s2idx].Offset
|
|
|
|
currS2.Length = s2[s2idx].Length
|
|
|
|
s2idx++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if currS1.Length == 0 && currS2.Length == 0 {
|
|
|
|
// The last spans of both set are zero length. Previous spans match.
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if currS1.Offset != currS2.Offset || currS1.Length != currS2.Length {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func allEmptySpans(s []Span) bool {
|
|
|
|
for _, ss := range s {
|
|
|
|
if ss.Length > 0 {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
histograms: Add Compact method to the normal integer Histogram
And use the new method to call to compact Histograms during
parsing. This happens for both `Histogram` and `FloatHistogram`. In
this way, if targets decide to optimize the exposition size by merging
spans with empty buckets in between, we still get a normalized
results. It will also normalize away any valid but weird
representations like empty spans, spans with offset zero, and empty
buckets at the start or end of a span.
The implementation seemed easy at first as it just turns the
`compactBuckets` helper into a generic function (which now got its own
file). However, the integer Histograms have delta buckets instead of
absolute buckets, which had to be treated specially in the generic
`compactBuckets` function. To make sure it works, I have added plenty
of explicit tests for `Histogram` in addition to the `FloatHistogram`
tests.
I have also updated the doc comment for the `Compact` method.
Based on the insights now expressed in the doc comment, compacting
with a maxEmptyBuckets > 0 is rarely useful. Therefore, this commit
also sets the value to 0 in the two cases we were using 3 so far. We
might still want to reconsider, so I don't want to remove the
maxEmptyBuckets parameter right now.
Signed-off-by: beorn7 <beorn@grafana.com>
2022-09-27 11:04:16 +00:00
|
|
|
// Compact works like FloatHistogram.Compact. See there for detailed
|
|
|
|
// explanations.
|
|
|
|
func (h *Histogram) Compact(maxEmptyBuckets int) *Histogram {
|
|
|
|
h.PositiveBuckets, h.PositiveSpans = compactBuckets(
|
|
|
|
h.PositiveBuckets, h.PositiveSpans, maxEmptyBuckets, true,
|
|
|
|
)
|
|
|
|
h.NegativeBuckets, h.NegativeSpans = compactBuckets(
|
|
|
|
h.NegativeBuckets, h.NegativeSpans, maxEmptyBuckets, true,
|
|
|
|
)
|
|
|
|
return h
|
|
|
|
}
|
|
|
|
|
2021-11-23 18:40:49 +00:00
|
|
|
// ToFloat returns a FloatHistogram representation of the Histogram. It is a
|
|
|
|
// deep copy (e.g. spans are not shared).
|
|
|
|
func (h *Histogram) ToFloat() *FloatHistogram {
|
|
|
|
var (
|
|
|
|
positiveSpans, negativeSpans []Span
|
|
|
|
positiveBuckets, negativeBuckets []float64
|
|
|
|
)
|
2021-11-29 07:54:23 +00:00
|
|
|
if len(h.PositiveSpans) != 0 {
|
2021-11-23 18:40:49 +00:00
|
|
|
positiveSpans = make([]Span, len(h.PositiveSpans))
|
|
|
|
copy(positiveSpans, h.PositiveSpans)
|
|
|
|
}
|
2021-11-29 07:54:23 +00:00
|
|
|
if len(h.NegativeSpans) != 0 {
|
2021-11-23 18:40:49 +00:00
|
|
|
negativeSpans = make([]Span, len(h.NegativeSpans))
|
|
|
|
copy(negativeSpans, h.NegativeSpans)
|
|
|
|
}
|
2021-11-29 07:54:23 +00:00
|
|
|
if len(h.PositiveBuckets) != 0 {
|
2021-11-23 18:40:49 +00:00
|
|
|
positiveBuckets = make([]float64, len(h.PositiveBuckets))
|
|
|
|
var current float64
|
|
|
|
for i, b := range h.PositiveBuckets {
|
|
|
|
current += float64(b)
|
|
|
|
positiveBuckets[i] = current
|
|
|
|
}
|
|
|
|
}
|
2021-11-29 07:54:23 +00:00
|
|
|
if len(h.NegativeBuckets) != 0 {
|
2021-11-23 18:40:49 +00:00
|
|
|
negativeBuckets = make([]float64, len(h.NegativeBuckets))
|
|
|
|
var current float64
|
|
|
|
for i, b := range h.NegativeBuckets {
|
|
|
|
current += float64(b)
|
|
|
|
negativeBuckets[i] = current
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &FloatHistogram{
|
2023-01-04 09:58:18 +00:00
|
|
|
CounterResetHint: h.CounterResetHint,
|
|
|
|
Schema: h.Schema,
|
|
|
|
ZeroThreshold: h.ZeroThreshold,
|
|
|
|
ZeroCount: float64(h.ZeroCount),
|
|
|
|
Count: float64(h.Count),
|
|
|
|
Sum: h.Sum,
|
|
|
|
PositiveSpans: positiveSpans,
|
|
|
|
NegativeSpans: negativeSpans,
|
|
|
|
PositiveBuckets: positiveBuckets,
|
|
|
|
NegativeBuckets: negativeBuckets,
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-03 14:47:59 +00:00
|
|
|
// Validate validates consistency between span and bucket slices. Also, buckets are checked
|
|
|
|
// against negative values.
|
|
|
|
// For histograms that have not observed any NaN values (based on IsNaN(h.Sum) check), a
|
|
|
|
// strict h.Count = nCount + pCount + h.ZeroCount check is performed.
|
|
|
|
// Otherwise, only a lower bound check will be done (h.Count >= nCount + pCount + h.ZeroCount),
|
|
|
|
// because NaN observations do not increment the values of buckets (but they do increment
|
|
|
|
// the total h.Count).
|
|
|
|
func (h *Histogram) Validate() error {
|
|
|
|
if err := checkHistogramSpans(h.NegativeSpans, len(h.NegativeBuckets)); err != nil {
|
2023-11-08 03:49:39 +00:00
|
|
|
return fmt.Errorf("negative side: %w", err)
|
2023-11-03 14:47:59 +00:00
|
|
|
}
|
|
|
|
if err := checkHistogramSpans(h.PositiveSpans, len(h.PositiveBuckets)); err != nil {
|
2023-11-08 03:49:39 +00:00
|
|
|
return fmt.Errorf("positive side: %w", err)
|
2023-11-03 14:47:59 +00:00
|
|
|
}
|
|
|
|
var nCount, pCount uint64
|
|
|
|
err := checkHistogramBuckets(h.NegativeBuckets, &nCount, true)
|
|
|
|
if err != nil {
|
2023-11-08 03:49:39 +00:00
|
|
|
return fmt.Errorf("negative side: %w", err)
|
2023-11-03 14:47:59 +00:00
|
|
|
}
|
|
|
|
err = checkHistogramBuckets(h.PositiveBuckets, &pCount, true)
|
|
|
|
if err != nil {
|
2023-11-08 03:49:39 +00:00
|
|
|
return fmt.Errorf("positive side: %w", err)
|
2023-11-03 14:47:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
sumOfBuckets := nCount + pCount + h.ZeroCount
|
|
|
|
if math.IsNaN(h.Sum) {
|
|
|
|
if sumOfBuckets > h.Count {
|
2023-11-08 03:49:39 +00:00
|
|
|
return fmt.Errorf("%d observations found in buckets, but the Count field is %d: %w", sumOfBuckets, h.Count, ErrHistogramCountNotBigEnough)
|
2023-11-03 14:47:59 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if sumOfBuckets != h.Count {
|
2023-11-08 03:49:39 +00:00
|
|
|
return fmt.Errorf("%d observations found in buckets, but the Count field is %d: %w", sumOfBuckets, h.Count, ErrHistogramCountMismatch)
|
2023-11-03 14:47:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-11-09 20:45:04 +00:00
|
|
|
type regularBucketIterator struct {
|
2022-10-03 11:15:27 +00:00
|
|
|
baseBucketIterator[uint64, int64]
|
2021-11-09 20:45:04 +00:00
|
|
|
}
|
|
|
|
|
2023-10-09 06:40:59 +00:00
|
|
|
func newRegularBucketIterator(spans []Span, buckets []int64, schema int32, positive bool) regularBucketIterator {
|
2022-10-03 11:15:27 +00:00
|
|
|
i := baseBucketIterator[uint64, int64]{
|
|
|
|
schema: schema,
|
|
|
|
spans: spans,
|
|
|
|
buckets: buckets,
|
|
|
|
positive: positive,
|
2021-11-09 20:45:04 +00:00
|
|
|
}
|
2023-10-09 06:40:59 +00:00
|
|
|
return regularBucketIterator{i}
|
2021-11-09 20:45:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *regularBucketIterator) Next() bool {
|
|
|
|
if r.spansIdx >= len(r.spans) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
span := r.spans[r.spansIdx]
|
|
|
|
// Seed currIdx for the first bucket.
|
|
|
|
if r.bucketsIdx == 0 {
|
|
|
|
r.currIdx = span.Offset
|
|
|
|
} else {
|
|
|
|
r.currIdx++
|
|
|
|
}
|
|
|
|
for r.idxInSpan >= span.Length {
|
|
|
|
// We have exhausted the current span and have to find a new
|
|
|
|
// one. We'll even handle pathologic spans of length 0.
|
|
|
|
r.idxInSpan = 0
|
|
|
|
r.spansIdx++
|
|
|
|
if r.spansIdx >= len(r.spans) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
span = r.spans[r.spansIdx]
|
|
|
|
r.currIdx += span.Offset
|
|
|
|
}
|
|
|
|
|
|
|
|
r.currCount += r.buckets[r.bucketsIdx]
|
|
|
|
r.idxInSpan++
|
|
|
|
r.bucketsIdx++
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2021-07-03 13:53:56 +00:00
|
|
|
type cumulativeBucketIterator struct {
|
2021-11-09 20:45:04 +00:00
|
|
|
h *Histogram
|
2021-07-03 13:53:56 +00:00
|
|
|
|
|
|
|
posSpansIdx int // Index in h.PositiveSpans we are in. -1 means 0 bucket.
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
posBucketsIdx int // Index in h.PositiveBuckets.
|
2021-07-03 13:53:56 +00:00
|
|
|
idxInSpan uint32 // Index in the current span. 0 <= idxInSpan < span.Length.
|
|
|
|
|
2021-11-09 20:45:04 +00:00
|
|
|
initialized bool
|
2021-07-03 13:53:56 +00:00
|
|
|
currIdx int32 // The actual bucket index after decoding from spans.
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
currUpper float64 // The upper boundary of the current bucket.
|
2021-07-03 13:53:56 +00:00
|
|
|
currCount int64 // Current non-cumulative count for the current bucket. Does not apply for empty bucket.
|
|
|
|
currCumulativeCount uint64 // Current "cumulative" count for the current bucket.
|
|
|
|
|
|
|
|
// Between 2 spans there could be some empty buckets which
|
|
|
|
// still needs to be counted for cumulative buckets.
|
|
|
|
// When we hit the end of a span, we use this to iterate
|
|
|
|
// through the empty buckets.
|
|
|
|
emptyBucketCount int32
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *cumulativeBucketIterator) Next() bool {
|
|
|
|
if c.posSpansIdx == -1 {
|
|
|
|
// Zero bucket.
|
|
|
|
c.posSpansIdx++
|
|
|
|
if c.h.ZeroCount == 0 {
|
|
|
|
return c.Next()
|
|
|
|
}
|
|
|
|
|
Style cleanup of all the changes in sparsehistogram so far
A lot of this code was hacked together, literally during a
hackathon. This commit intends not to change the code substantially,
but just make the code obey the usual style practices.
A (possibly incomplete) list of areas:
* Generally address linter warnings.
* The `pgk` directory is deprecated as per dev-summit. No new packages should
be added to it. I moved the new `pkg/histogram` package to `model`
anticipating what's proposed in #9478.
* Make the naming of the Sparse Histogram more consistent. Including
abbreviations, there were just too many names for it: SparseHistogram,
Histogram, Histo, hist, his, shs, h. The idea is to call it "Histogram" in
general. Only add "Sparse" if it is needed to avoid confusion with
conventional Histograms (which is rare because the TSDB really has no notion
of conventional Histograms). Use abbreviations only in local scope, and then
really abbreviate (not just removing three out of seven letters like in
"Histo"). This is in the spirit of
https://github.com/golang/go/wiki/CodeReviewComments#variable-names
* Several other minor name changes.
* A lot of formatting of doc comments. For one, following
https://github.com/golang/go/wiki/CodeReviewComments#comment-sentences
, but also layout question, anticipating how things will look like
when rendered by `godoc` (even where `godoc` doesn't render them
right now because they are for unexported types or not a doc comment
at all but just a normal code comment - consistency is queen!).
* Re-enabled `TestQueryLog` and `TestEndopints` (they pass now,
leaving them disabled was presumably an oversight).
* Bucket iterator for histogram.Histogram is now created with a
method.
* HistogramChunk.iterator now allows iterator recycling. (I think
@dieterbe only commented it out because he was confused by the
question in the comment.)
* HistogramAppender.Append panics now because we decided to treat
staleness marker differently.
Signed-off-by: beorn7 <beorn@grafana.com>
2021-10-09 13:57:07 +00:00
|
|
|
c.currUpper = c.h.ZeroThreshold
|
2021-07-03 13:53:56 +00:00
|
|
|
c.currCount = int64(c.h.ZeroCount)
|
|
|
|
c.currCumulativeCount = uint64(c.currCount)
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.posSpansIdx >= len(c.h.PositiveSpans) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if c.emptyBucketCount > 0 {
|
|
|
|
// We are traversing through empty buckets at the moment.
|
2021-11-09 20:45:04 +00:00
|
|
|
c.currUpper = getBound(c.currIdx, c.h.Schema)
|
2021-07-03 13:53:56 +00:00
|
|
|
c.currIdx++
|
|
|
|
c.emptyBucketCount--
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
span := c.h.PositiveSpans[c.posSpansIdx]
|
2021-11-09 20:45:04 +00:00
|
|
|
if c.posSpansIdx == 0 && !c.initialized {
|
2021-11-23 18:40:49 +00:00
|
|
|
// Initializing.
|
2021-07-03 13:53:56 +00:00
|
|
|
c.currIdx = span.Offset
|
2021-11-09 20:45:04 +00:00
|
|
|
// The first bucket is an absolute value and not a delta with Zero bucket.
|
2021-07-03 13:53:56 +00:00
|
|
|
c.currCount = 0
|
2021-11-09 20:45:04 +00:00
|
|
|
c.initialized = true
|
2021-07-03 13:53:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
c.currCount += c.h.PositiveBuckets[c.posBucketsIdx]
|
|
|
|
c.currCumulativeCount += uint64(c.currCount)
|
2021-11-09 20:45:04 +00:00
|
|
|
c.currUpper = getBound(c.currIdx, c.h.Schema)
|
2021-07-03 13:53:56 +00:00
|
|
|
|
|
|
|
c.posBucketsIdx++
|
|
|
|
c.idxInSpan++
|
|
|
|
c.currIdx++
|
|
|
|
if c.idxInSpan >= span.Length {
|
|
|
|
// Move to the next span. This one is done.
|
|
|
|
c.posSpansIdx++
|
|
|
|
c.idxInSpan = 0
|
|
|
|
if c.posSpansIdx < len(c.h.PositiveSpans) {
|
|
|
|
c.emptyBucketCount = c.h.PositiveSpans[c.posSpansIdx].Offset
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
2021-11-09 20:45:04 +00:00
|
|
|
|
2022-10-03 11:15:27 +00:00
|
|
|
func (c *cumulativeBucketIterator) At() Bucket[uint64] {
|
|
|
|
return Bucket[uint64]{
|
2021-11-09 20:45:04 +00:00
|
|
|
Upper: c.currUpper,
|
|
|
|
Lower: math.Inf(-1),
|
|
|
|
UpperInclusive: true,
|
|
|
|
LowerInclusive: true,
|
|
|
|
Count: c.currCumulativeCount,
|
|
|
|
Index: c.currIdx - 1,
|
2021-07-03 13:53:56 +00:00
|
|
|
}
|
|
|
|
}
|
2023-11-08 13:43:05 +00:00
|
|
|
|
|
|
|
// ReduceResolution reduces the histogram's spans, buckets into target schema.
|
|
|
|
// The target schema must be smaller than the current histogram's schema.
|
|
|
|
func (h *Histogram) ReduceResolution(targetSchema int32) *Histogram {
|
|
|
|
h.PositiveSpans, h.PositiveBuckets = reduceResolution(
|
|
|
|
h.PositiveSpans, h.PositiveBuckets, h.Schema, targetSchema, true,
|
|
|
|
)
|
|
|
|
h.NegativeSpans, h.NegativeBuckets = reduceResolution(
|
|
|
|
h.NegativeSpans, h.NegativeBuckets, h.Schema, targetSchema, true,
|
|
|
|
)
|
2023-11-10 13:33:34 +00:00
|
|
|
h.Schema = targetSchema
|
2023-11-08 13:43:05 +00:00
|
|
|
return h
|
|
|
|
}
|