From d11ee103acd9eb46a28b621828604b2446a0887a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=B6rgy=20Krajcsovits?= Date: Mon, 6 Oct 2025 21:44:34 +0200 Subject: [PATCH] perf(tsdb): reuse map of sample types to speed up head appender MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While investigating +10% CPU in v3.7 release, found that ~5% is from expanding the types map. Try reuse. Also fix a linter error. Signed-off-by: György Krajcsovits --- tsdb/head.go | 1 + tsdb/head_append.go | 21 ++++++++++++++++++++- util/testutil/synctest/disabled.go | 2 +- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tsdb/head.go b/tsdb/head.go index 45f425cea9..f3242b8ba7 100644 --- a/tsdb/head.go +++ b/tsdb/head.go @@ -93,6 +93,7 @@ type Head struct { floatHistogramsPool zeropool.Pool[[]record.RefFloatHistogramSample] metadataPool zeropool.Pool[[]record.RefMetadata] seriesPool zeropool.Pool[[]*memSeries] + typeMapPool zeropool.Pool[map[chunks.HeadSeriesRef]sampleType] bytesPool zeropool.Pool[[]byte] memChunkPool sync.Pool diff --git a/tsdb/head_append.go b/tsdb/head_append.go index 659c09f7e7..9f930a763f 100644 --- a/tsdb/head_append.go +++ b/tsdb/head_append.go @@ -173,7 +173,7 @@ func (h *Head) appender() *headAppender { oooTimeWindow: h.opts.OutOfOrderTimeWindow.Load(), seriesRefs: h.getRefSeriesBuffer(), series: h.getSeriesBuffer(), - typesInBatch: map[chunks.HeadSeriesRef]sampleType{}, + typesInBatch: h.getTypeMap(), appendID: appendID, cleanupAppendIDsBelow: cleanupAppendIDsBelow, } @@ -297,6 +297,19 @@ func (h *Head) putSeriesBuffer(b []*memSeries) { h.seriesPool.Put(b[:0]) } +func (h *Head) getTypeMap() map[chunks.HeadSeriesRef]sampleType { + b := h.typeMapPool.Get() + if b == nil { + return make(map[chunks.HeadSeriesRef]sampleType) + } + return b +} + +func (h *Head) putTypeMap(b map[chunks.HeadSeriesRef]sampleType) { + clear(b) + h.typeMapPool.Put(b) +} + func (h *Head) getBytesBuffer() []byte { b := h.bytesPool.Get() if b == nil { @@ -1687,8 +1700,13 @@ func (a *headAppender) Commit() (err error) { h := a.head defer func() { + if a.closed { + // Don't double-close in case Rollback() was called. + return + } h.putRefSeriesBuffer(a.seriesRefs) h.putSeriesBuffer(a.series) + h.putTypeMap(a.typesInBatch) a.closed = true }() @@ -2216,6 +2234,7 @@ func (a *headAppender) Rollback() (err error) { a.closed = true h.putRefSeriesBuffer(a.seriesRefs) h.putSeriesBuffer(a.series) + h.putTypeMap(a.typesInBatch) }() var series *memSeries diff --git a/util/testutil/synctest/disabled.go b/util/testutil/synctest/disabled.go index 2cdcc72e07..e87454afcf 100644 --- a/util/testutil/synctest/disabled.go +++ b/util/testutil/synctest/disabled.go @@ -19,7 +19,7 @@ import ( "testing" ) -func Test(t *testing.T, f func(t *testing.T)) { +func Test(t *testing.T, _ func(t *testing.T)) { t.Skip("goexperiment.synctest is not enabled") }