ronantakizawa/codereview-bench huggingface dataset:
Repository: prometheus/prometheus
File: rules/group.go (Go)

Code before:
	if ctrl == nil {
		ctrl = sequentialRuleEvalController{}
	}

	batches := ctrl.SplitGroupIntoBatches(ctx, g)
	if len(batches) == 0 {
		// Sequential evaluation when batches aren't set.
		// This is the behaviour without a defined RuleConcurrencyController
		for i, rule := range g.rules {
			// Check if the group has been stopped.
			select {
			case <-g.done:
				return
			default:
			}
			eval(i, rule, nil)
		}
	} else {
		// Concurrent evaluation.
		for _, batch := range ctrl.SplitGroupIntoBatches(ctx, g) {
			for _, ruleIndex := range batch {
				// Check if the group has been stopped.
				select {
				case <-g.done:
					return
				default:
				}
				rule := g.rules[ruleIndex]
				if len(batch) > 1 && ctrl.Allow(ctx, g, rule) {
					wg.Add(1)

					go eval(ruleIndex, rule, func() {
						wg.Done()
						ctrl.Done(ctx)
					})
				} else {
					eval(ruleIndex, rule, nil)
				}
			}
			// It is important that we finish processing any rules in this current batch - before we move into the next one.
			wg.Wait()
		}
	}

	g.metrics.GroupSamples.WithLabelValues(GroupKey(g.File(), g.Name())).Set(samplesTotal.Load())
	g.cleanupStaleSeries(ctx, ts)
}

func (g *Group) QueryOffset() time.Duration {
	if g.queryOffset != nil {
		return *g.queryOffset

Review comment (suggestion):
I think we need to `wg.Wait()` here to make sure that we finish any that are in-transit before we return.

Code after:
	if ctrl == nil {
		ctrl = sequentialRuleEvalController{}
	}

	batches := ctrl.SplitGroupIntoBatches(ctx, g)
	if len(batches) == 0 {
		// Sequential evaluation when batches aren't set.
		// This is the behaviour without a defined RuleConcurrencyController
		for i, rule := range g.rules {
			// Check if the group has been stopped.
			select {
			case <-g.done:
				return
			default:
			}
			eval(i, rule, nil)
		}
	} else {
		// Concurrent evaluation.
		for _, batch := range batches {
			for _, ruleIndex := range batch {
				// Check if the group has been stopped.
				select {
				case <-g.done:
					wg.Wait()
					return
				default:
				}
				rule := g.rules[ruleIndex]
				if len(batch) > 1 && ctrl.Allow(ctx, g, rule) {
					wg.Add(1)

					go eval(ruleIndex, rule, func() {
						wg.Done()
						ctrl.Done(ctx)
					})
				} else {
					eval(ruleIndex, rule, nil)
				}
			}
			// It is important that we finish processing any rules in this current batch - before we move into the next one.
			wg.Wait()
		}
	}

	g.metrics.GroupSamples.WithLabelValues(GroupKey(g.File(), g.Name())).Set(samplesTotal.Load())
	g.cleanupStaleSeries(ctx, ts)
}

func (g *Group) QueryOffset() time.Duration {
	if g.queryOffset != nil {
Repository: prometheus/prometheus
File: rules/group.go (Go)

Code before:
		select {
		case <-g.done:
			return
		default:
			select {
			case <-g.done:
				return
			case <-tick.C:
				missed := (time.Since(evalTimestamp) / g.interval) - 1
				if missed > 0 {
					g.metrics.IterationsMissed.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed))
					g.metrics.IterationsScheduled.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed))
				}
				evalTimestamp = evalTimestamp.Add((missed + 1) * g.interval)

				g.evalIterationFunc(ctx, g, evalTimestamp)
			}
		}
	}
}

func (g *Group) stopAsync() {
	close(g.done)
}

func (g *Group) awaitStopped() {
	<-g.terminated
}

func (g *Group) stop() {
	close(g.done)
	<-g.terminated
}

func (g *Group) hash() uint64 {
	l := labels.New(
		labels.Label{Name: "name", Value: g.name},
		labels.Label{Name: "file", Value: g.file},
	)
	return l.Hash()
}

// AlertingRules returns the list of the group's alerting rules.
func (g *Group) AlertingRules() []*AlertingRule {
	g.mtx.Lock()
	defer g.mtx.Unlock()

	var alerts []*AlertingRule
	for _, rule := range g.rules {
		if alertingRule, ok := rule.(*AlertingRule); ok {
			alerts = append(alerts, alertingRule)

Review comment (suggestion):
```suggestion
func (g *Group) waitStopped() {
```
I don't see it as asynchronous.
Maybe we don't even need those wrappers, we can just directly close and wait for the channels as we do elsewhere.
Or make use of the wrappers in `stop()`

Code after:
		select {
		case <-g.done:
			return
		default:
			select {
			case <-g.done:
				return
			case <-tick.C:
				missed := (time.Since(evalTimestamp) / g.interval) - 1
				if missed > 0 {
					g.metrics.IterationsMissed.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed))
					g.metrics.IterationsScheduled.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed))
				}
				evalTimestamp = evalTimestamp.Add((missed + 1) * g.interval)

				g.evalIterationFunc(ctx, g, evalTimestamp)
			}
		}
	}
}

func (g *Group) stopAsync() {
	close(g.done)
}

func (g *Group) waitStopped() {
	<-g.terminated
}

func (g *Group) stop() {
	g.stopAsync()
	g.waitStopped()
}

func (g *Group) hash() uint64 {
	l := labels.New(
		labels.Label{Name: "name", Value: g.name},
		labels.Label{Name: "file", Value: g.file},
	)
	return l.Hash()
}

// AlertingRules returns the list of the group's alerting rules.
func (g *Group) AlertingRules() []*AlertingRule {
	g.mtx.Lock()
	defer g.mtx.Unlock()

	var alerts []*AlertingRule
	for _, rule := range g.rules {
		if alertingRule, ok := rule.(*AlertingRule); ok {
			alerts = append(alerts, alertingRule)
Repository: prometheus/prometheus
File: web/api/v1/api.go (Go)

Code before:
	}
	var set storage.SeriesSet

	if len(matcherSets) > 1 {
		var sets []storage.SeriesSet
		for _, mset := range matcherSets {
			// We need to sort this select results to merge (deduplicate) the series sets later.
			s := q.Select(ctx, true, hints, mset...)
			sets = append(sets, s)
		}
		set = storage.NewMergeSeriesSet(sets, 0, storage.ChainedSeriesMerge)
	} else {
		// At this point at least one match exists.
		set = q.Select(ctx, false, hints, matcherSets[0]...)
	}

	metrics := []labels.Labels{}

	warnings := set.Warnings()

	for set.Next() {
		if err := ctx.Err(); err != nil {
			return apiFuncResult{nil, returnAPIError(err), warnings, closer}
		}
		metrics = append(metrics, set.At().Labels())

		if limit > 0 && len(metrics) > limit {
			metrics = metrics[:limit]
			warnings.Add(errors.New("results truncated due to limit"))
			return apiFuncResult{metrics, nil, warnings, closer}
		}
	}
	if set.Err() != nil {
		return apiFuncResult{nil, returnAPIError(set.Err()), warnings, closer}
	}

	return apiFuncResult{metrics, nil, warnings, closer}
}

func (api *API) dropSeries(_ *http.Request) apiFuncResult {
	return apiFuncResult{nil, &apiError{errorInternal, errors.New("not implemented")}, nil, nil}
}

// Target has the information for one target.
type Target struct {
	// Labels before any processing.
	DiscoveredLabels labels.Labels `json:"discoveredLabels"`
	// Any labels that are added to this target and its metrics.
	Labels labels.Labels `json:"labels"`

	ScrapePool string `json:"scrapePool"`

Review comment (suggestion):
```suggestion
		if i%skipContextCheckIterations == 0 {
```

Code after:
		End:   timestamp.FromTime(end),
		Func:  "series", // There is no series function, this token is used for lookups that don't need samples.
		Limit: toHintLimit(limit),
	}
	var set storage.SeriesSet

	if len(matcherSets) > 1 {
		var sets []storage.SeriesSet
		for _, mset := range matcherSets {
			// We need to sort this select results to merge (deduplicate) the series sets later.
			s := q.Select(ctx, true, hints, mset...)
			sets = append(sets, s)
		}
		set = storage.NewMergeSeriesSet(sets, 0, storage.ChainedSeriesMerge)
	} else {
		// At this point at least one match exists.
		set = q.Select(ctx, false, hints, matcherSets[0]...)
	}

	metrics := []labels.Labels{}

	warnings := set.Warnings()

	i := 1
	for set.Next() {
		if i%checkContextEveryNIterations == 0 {
			if err := ctx.Err(); err != nil {
				return apiFuncResult{nil, returnAPIError(err), warnings, closer}
			}
		}
		i++

		metrics = append(metrics, set.At().Labels())

		if limit > 0 && len(metrics) > limit {
			metrics = metrics[:limit]
			warnings.Add(errors.New("results truncated due to limit"))
			return apiFuncResult{metrics, nil, warnings, closer}
		}
	}
	if set.Err() != nil {
		return apiFuncResult{nil, returnAPIError(set.Err()), warnings, closer}
	}

	return apiFuncResult{metrics, nil, warnings, closer}
}

func (api *API) dropSeries(_ *http.Request) apiFuncResult {
	return apiFuncResult{nil, &apiError{errorInternal, errors.New("not implemented")}, nil, nil}
}
Repository: prometheus/prometheus
File: promql/engine.go (Go)

Code before:
func detectHistogramStatsDecoding(expr parser.Expr) {
	parser.Inspect(expr, func(node parser.Node, path []parser.Node) error {
		if n, ok := node.(*parser.BinaryExpr); ok {
			detectHistogramStatsDecoding(n.LHS)
			detectHistogramStatsDecoding(n.RHS)
			return errors.New("stop")
		}

		n, ok := (node).(*parser.VectorSelector)
		if !ok {
			return nil
		}

		for _, p := range path {
			call, ok := p.(*parser.Call)
			if !ok {
				continue
			}
			fn := call.Func.Name
			if fn == "histogram_count" || fn == "histogram_sum" || fn == "histogram_avg" {
				n.SkipHistogramBuckets = true
				break
			}
			if fn == "histogram_quantile" || fn == "histogram_fraction" {
				n.SkipHistogramBuckets = false
				break
			}
		}
		return errors.New("stop")
	})
}

func makeInt64Pointer(val int64) *int64 {
	valp := new(int64)
	*valp = val
	return valp
}

// RatioSampler allows unit-testing (previously: Randomizer).
type RatioSampler interface {
	// Return this sample "offset" between [0.0, 1.0]
	sampleOffset(ts int64, sample *Sample) float64
	AddRatioSample(r float64, sample *Sample) bool
}

// HashRatioSampler uses Hash(labels.String()) / maxUint64 as a "deterministic"
// value in [0.0, 1.0].
type HashRatioSampler struct{}

var ratiosampler RatioSampler = NewHashRatioSampler()


Review comment (suggestion):
Maybe let's write this as a `switch` statement after all?

```Go
			switch call.Func.Name {
			case "histogram_count", "histogram_sum", "histogram_avg":
				n.SkipHistogramBuckets = true
			case "histogram_quantile", "histogram_fraction":
				n.SkipHistogramBuckets = false
			default:
				continue
			}
			break
```

Code after:
func detectHistogramStatsDecoding(expr parser.Expr) {
	parser.Inspect(expr, func(node parser.Node, path []parser.Node) error {
		if n, ok := node.(*parser.BinaryExpr); ok {
			detectHistogramStatsDecoding(n.LHS)
			detectHistogramStatsDecoding(n.RHS)
			return errors.New("stop")
		}

		n, ok := (node).(*parser.VectorSelector)
		if !ok {
			return nil
		}

		for _, p := range path {
			call, ok := p.(*parser.Call)
			if !ok {
				continue
			}
			switch call.Func.Name {
			case "histogram_count", "histogram_sum", "histogram_avg":
				n.SkipHistogramBuckets = true
			case "histogram_quantile", "histogram_fraction":
				n.SkipHistogramBuckets = false
			default:
				continue
			}
			break
		}
		return errors.New("stop")
	})
}

func makeInt64Pointer(val int64) *int64 {
	valp := new(int64)
	*valp = val
	return valp
}

// RatioSampler allows unit-testing (previously: Randomizer).
type RatioSampler interface {
	// Return this sample "offset" between [0.0, 1.0]
	sampleOffset(ts int64, sample *Sample) float64
	AddRatioSample(r float64, sample *Sample) bool
}

// HashRatioSampler uses Hash(labels.String()) / maxUint64 as a "deterministic"
// value in [0.0, 1.0].
type HashRatioSampler struct{}

var ratiosampler RatioSampler = NewHashRatioSampler()
Repository: prometheus/prometheus
File: promql/functions.go (Go)

Code before:

	// Add last 2 float samples if exists.
	for i := max(0, len(samples.Floats)-2); i < len(samples.Floats); i++ {
		ss = append(ss, Sample{
			F: samples.Floats[i].F,
			T: samples.Floats[i].T,
		})
	}

	// Add last 2 histogram samples into their correct position if exists.
	for i := max(0, len(samples.Histograms)-2); i < len(samples.Histograms); i++ {
		s := Sample{
			H: samples.Histograms[i].H,
			T: samples.Histograms[i].T,
		}
		switch {
		case len(ss) == 0:
			ss = append(ss, s)
		case len(ss) == 1:
			if s.T < ss[0].T {
				ss = append([]Sample{s}, ss...)
			} else {
				ss = append(ss, s)
			}
		case s.T < ss[0].T:
			// discard.
		case s.T > ss[0].T && s.T < ss[1].T:
			ss[0] = s
		case s.T > ss[1].T:
			ss[0] = ss[1]
			ss[1] = s
		}
	}

	// No sense in trying to compute a rate without at least two points. Drop
	// this Vector element.
	// TODO: add RangeTooShortWarning
	if len(ss) < 2 {
		return out, nil
	}

	resultSample := ss[1]
	sampledInterval := ss[1].T - ss[0].T
	if sampledInterval == 0 {
		// Avoid dividing by 0.
		return out, nil
	}
	switch {
	case ss[1].H == nil && ss[0].H == nil:
		if isRate && ss[1].F < ss[0].F {
			// Counter reset.

Review comment (suggestion):
Capitalization nit:

```suggestion
			// Discard.
```

But maybe explain this more:

```suggestion
			// s is older then 1st, so disregard it.
```


Code after:
		annos      annotations.Annotations
	)

	// No sense in trying to compute a rate without at least two points. Drop
	// this Vector element.
	// TODO: add RangeTooShortWarning
	if len(samples.Floats)+len(samples.Histograms) < 2 {
		return out, nil
	}

	// Add the last 2 float samples if they exist.
	for i := max(0, len(samples.Floats)-2); i < len(samples.Floats); i++ {
		ss = append(ss, Sample{
			F: samples.Floats[i].F,
			T: samples.Floats[i].T,
		})
	}

	// Add the last 2 histogram samples into their correct position if they exist.
	for i := max(0, len(samples.Histograms)-2); i < len(samples.Histograms); i++ {
		s := Sample{
			H: samples.Histograms[i].H,
			T: samples.Histograms[i].T,
		}
		switch {
		case len(ss) == 0:
			ss = append(ss, s)
		case len(ss) == 1:
			if s.T < ss[0].T {
				ss = append([]Sample{s}, ss...)
			} else {
				ss = append(ss, s)
			}
		case s.T < ss[0].T:
			// s is older than 1st, so discard it.
		case s.T > ss[1].T:
			// s is newest, so add it as 2nd and make the old 2nd the new 1st.
			ss[0] = ss[1]
			ss[1] = s
		default:
			// In all other cases, we just make s the new 1st.
			// This establishes a correct order, even in the (irregular)
			// case of equal timestamps.
			ss[0] = s
		}
	}

	resultSample := ss[1]
	sampledInterval := ss[1].T - ss[0].T
	if sampledInterval == 0 {
		// Avoid dividing by 0.
Repository: prometheus/prometheus
File: notifier/notifier.go (Go)

Code before:
				return false
			}
		}

		if len(ams.cfg.AlertRelabelConfigs) > 0 {
			// We can't use the cached values on the next iteration.
			cachedPayload = nil
		}

		for _, am := range ams.ams {
			wg.Add(1)

			ctx, cancel := context.WithTimeout(context.Background(), time.Duration(ams.cfg.Timeout))
			defer cancel()

			go func(ctx context.Context, k string, client *http.Client, url string, payload []byte, count int) {
				err := n.sendOne(ctx, client, url, payload)
				if err != nil {
					n.logger.Error("Error sending alerts", "alertmanager", url, "count", count, "err", err)
					n.metrics.errors.WithLabelValues(url).Add(float64(count))
				}

				lock.Lock()
				numAttempt[k]++
				if err == nil {
					numSuccess[k]++
				}
				lock.Unlock()

				n.metrics.latency.WithLabelValues(url).Observe(time.Since(begin).Seconds())
				n.metrics.sent.WithLabelValues(url).Add(float64(count))

				wg.Done()
			}(ctx, k, ams.client, am.url().String(), payload, len(amAlerts))
		}

		ams.mtx.RUnlock()
	}

	wg.Wait()

	// Return false if there are any sets which were attempted (e.g. not filtered
	// out) but have no successes.
	for k := range numAttempt {
		if numAttempt[k] > 0 && numSuccess[k] == 0 {
			return false
		}
	}
	return true
}


Review comment (performance):
Not related to the PR; I don't think we should we incrementing `.sent` in here, maybe not `latency` either.
I'll open an issue to discuss those and `dropped` as well and we can take care of them in a follow-up


Code after:
		}

		if len(ams.cfg.AlertRelabelConfigs) > 0 {
			// We can't use the cached values on the next iteration.
			cachedPayload = nil
		}

		// Being here means len(ams.ams) > 0
		amSetCovered.Store(k, false)
		for _, am := range ams.ams {
			wg.Add(1)

			ctx, cancel := context.WithTimeout(context.Background(), time.Duration(ams.cfg.Timeout))
			defer cancel()

			go func(ctx context.Context, k string, client *http.Client, url string, payload []byte, count int) {
				err := n.sendOne(ctx, client, url, payload)
				if err != nil {
					n.logger.Error("Error sending alerts", "alertmanager", url, "count", count, "err", err)
					n.metrics.errors.WithLabelValues(url).Add(float64(count))
				} else {
					amSetCovered.CompareAndSwap(k, false, true)
				}

				n.metrics.latency.WithLabelValues(url).Observe(time.Since(begin).Seconds())
				n.metrics.sent.WithLabelValues(url).Add(float64(count))

				wg.Done()
			}(ctx, k, ams.client, am.url().String(), payload, len(amAlerts))
		}

		ams.mtx.RUnlock()
	}

	wg.Wait()

	// Return false if there are any sets which were attempted (e.g. not filtered
	// out) but have no successes.
	allAmSetsCovered := true
	amSetCovered.Range(func(_, value any) bool {
		if !value.(bool) {
			allAmSetsCovered = false
			return false
		}
		return true
	})

	return allAmSetsCovered
}

func alertsToOpenAPIAlerts(alerts []*Alert) models.PostableAlerts {
Repository: prometheus/prometheus
File: cmd/promtool/tsdb.go (Go)

Code before:
			ts, val := it.At()
			fmt.Printf("%s%s %g %.3f\n", metricName, CondensedString(lbs), val, float64(ts)/1000)
		}
		if it.Err() != nil {
			return ss.Err()
		}
	}
	fmt.Println("# EOF")
	return nil
}

func checkErr(err error) int {
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	return 0
}

func backfillOpenMetrics(path, outputDir string, humanReadable, quiet bool, maxBlockDuration time.Duration, customLabels map[string]string) int {
	var buf []byte
	info, err := os.Stat(path)
	if err != nil {
		return checkErr(err)
	}
	if info.Mode()&os.ModeNamedPipe != 0 {
		// Read the pipe chunks by chunks as it cannot be mmap-ed
		buf, err = os.ReadFile(path)
		if err != nil {
			return checkErr(err)
		}
	} else {
		inputFile, err := fileutil.OpenMmapFile(path)
		if err != nil {
			return checkErr(err)
		}
		defer inputFile.Close()
		buf = inputFile.Bytes()
	}

	if err := os.MkdirAll(outputDir, 0o777); err != nil {
		return checkErr(fmt.Errorf("create output dir: %w", err))
	}

	return checkErr(backfill(5000, buf, outputDir, humanReadable, quiet, maxBlockDuration, customLabels))
}

func displayHistogram(dataType string, datas []int, total int) {
	if len(datas) == 0 {
		fmt.Printf("%s: N/A\n\n", dataType)
		return

Review comment (suggestion):
`info.Mode()&(os.ModeNamedPipe|os.ModeCharDevice)`

Please; it's confusing to support one form of `/dev/stdin` but not the other. (It's probably not that useful, as it's mostly only going to be a chardevice if someone is pasting stuff in, but potentially avoids a confusing error if someone is testing a pipeline, certainly this is how people expect Unix pipes to behave.)

Code after:
			ts, val := it.At()
			fmt.Printf("%s%s %g %.3f\n", metricName, CondensedString(lbs), val, float64(ts)/1000)
		}
		if it.Err() != nil {
			return ss.Err()
		}
	}
	fmt.Println("# EOF")
	return nil
}

func checkErr(err error) int {
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}
	return 0
}

func backfillOpenMetrics(path, outputDir string, humanReadable, quiet bool, maxBlockDuration time.Duration, customLabels map[string]string) int {
	var buf []byte
	info, err := os.Stat(path)
	if err != nil {
		return checkErr(err)
	}
	if info.Mode()&(os.ModeNamedPipe|os.ModeCharDevice) != 0 {
		// Read the pipe chunks by chunks as it cannot be mmap-ed
		buf, err = os.ReadFile(path)
		if err != nil {
			return checkErr(err)
		}
	} else {
		inputFile, err := fileutil.OpenMmapFile(path)
		if err != nil {
			return checkErr(err)
		}
		defer inputFile.Close()
		buf = inputFile.Bytes()
	}

	if err := os.MkdirAll(outputDir, 0o777); err != nil {
		return checkErr(fmt.Errorf("create output dir: %w", err))
	}

	return checkErr(backfill(5000, buf, outputDir, humanReadable, quiet, maxBlockDuration, customLabels))
}

func displayHistogram(dataType string, datas []int, total int) {
	if len(datas) == 0 {
		fmt.Printf("%s: N/A\n\n", dataType)
		return
Repository: prometheus/prometheus
File: model/textparse/benchmark_test.go (Go)

Code before:
			}
			decSamples = decSamples[:0]
		}
	}
}

func readTestdataFile(tb testing.TB, file string) []byte {
	tb.Helper()

	f, err := os.Open(filepath.Join("testdata", file))
	require.NoError(tb, err)

	tb.Cleanup(func() {
		_ = f.Close()
	})
	buf, err := io.ReadAll(f)
	require.NoError(tb, err)
	return buf
}

/*
	export bench=v3 && go test ./model/textparse/... \
		 -run '^$' -bench '^BenchmarkCreatedTimestampPromProto' \
		 -benchtime 2s -count 6 -cpu 2 -benchmem -timeout 999m \
	 | tee ${bench}.txt
*/
func BenchmarkCreatedTimestampPromProto(b *testing.B) {
	data := createTestProtoBuf(b).Bytes()

	st := labels.NewSymbolTable()
	p := NewProtobufParser(data, true, st)

	found := false
Inner:
	for {
		t, err := p.Next()
		switch t {
		case EntryInvalid:
			b.Fatal(err)
		case EntryType:
			m, _ := p.Type()
			if string(m) == "go_memstats_alloc_bytes_total" {
				found = true
				break Inner
			}
		// Parser impl requires this (bug?)
		case EntryHistogram:
			_, _, _, _ = p.Histogram()
		case EntrySeries:
			_, _, _ = p.Series()
		}

Review comment (suggestion):
Suggest this belongs in a doc file about running benchmarks; it is not special to this one benchmark.
(Also I don't know what the `bench=v3` does)

Code after:
			}
			decSamples = decSamples[:0]
		}
	}
}

func readTestdataFile(tb testing.TB, file string) []byte {
	tb.Helper()

	f, err := os.Open(filepath.Join("testdata", file))
	require.NoError(tb, err)

	tb.Cleanup(func() {
		_ = f.Close()
	})
	buf, err := io.ReadAll(f)
	require.NoError(tb, err)
	return buf
}

/*
	export bench=v1 && go test ./model/textparse/... \
		 -run '^$' -bench '^BenchmarkCreatedTimestampPromProto' \
		 -benchtime 2s -count 6 -cpu 2 -benchmem -timeout 999m \
	 | tee ${bench}.txt
*/
func BenchmarkCreatedTimestampPromProto(b *testing.B) {
	data := createTestProtoBuf(b).Bytes()

	st := labels.NewSymbolTable()
	p := NewProtobufParser(data, true, st)

	found := false
Inner:
	for {
		t, err := p.Next()
		switch t {
		case EntryInvalid:
			b.Fatal(err)
		case EntryType:
			m, _ := p.Type()
			if string(m) == "go_memstats_alloc_bytes_total" {
				found = true
				break Inner
			}
		// Parser impl requires this (bug?)
		case EntryHistogram:
			_, _, _, _ = p.Histogram()
		case EntrySeries:
			_, _, _ = p.Series()
		}