From b65f1b65605882cbbc21552ad8f280b3bc3abfef Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 16 Sep 2024 08:48:49 +0100 Subject: [PATCH 1/4] TSDB: Improve xor-chunk benchmarks Benchmarks must do the same work N times. Run 3 cases, where the values are constant, vary a bit, and vary a lot. Also aim for 120 samples same as TSDB default. Signed-off-by: Bryan Boreham --- tsdb/chunkenc/chunk_test.go | 50 +++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/tsdb/chunkenc/chunk_test.go b/tsdb/chunkenc/chunk_test.go index b72492a08b..6319db6eec 100644 --- a/tsdb/chunkenc/chunk_test.go +++ b/tsdb/chunkenc/chunk_test.go @@ -251,54 +251,62 @@ func benchmarkIterator(b *testing.B, newChunk func() Chunk) { } } +func newXORChunk() Chunk { + return NewXORChunk() +} + func BenchmarkXORIterator(b *testing.B) { - benchmarkIterator(b, func() Chunk { - return NewXORChunk() - }) + benchmarkIterator(b, newXORChunk) } func BenchmarkXORAppender(b *testing.B) { - benchmarkAppender(b, func() Chunk { - return NewXORChunk() + r := rand.New(rand.NewSource(1)) + b.Run("constant", func(b *testing.B) { + benchmarkAppender(b, func() (int64, float64) { + return 1000, 0 + }, newXORChunk) + }) + b.Run("random steps", func(b *testing.B) { + benchmarkAppender(b, func() (int64, float64) { + return int64(r.Intn(100) - 50 + 15000), // 15 seconds +- up to 100ms of jitter. + float64(r.Intn(100) - 50) // Varying from -50 to +50 in 100 discrete steps. + }, newXORChunk) + }) + b.Run("random 0-1", func(b *testing.B) { + benchmarkAppender(b, func() (int64, float64) { + return int64(r.Intn(100) - 50 + 15000), // 15 seconds +- up to 100ms of jitter. + r.Float64() // Random between 0 and 1.0. + }, newXORChunk) }) } -func benchmarkAppender(b *testing.B, newChunk func() Chunk) { +func benchmarkAppender(b *testing.B, deltas func() (int64, float64), newChunk func() Chunk) { var ( t = int64(1234123324) v = 1243535.123 ) + const nSamples = 120 // Same as tsdb.DefaultSamplesPerChunk. var exp []pair - for i := 0; i < b.N; i++ { - // t += int64(rand.Intn(10000) + 1) - t += int64(1000) - // v = rand.Float64() - v += float64(100) + for i := 0; i < nSamples; i++ { + dt, dv := deltas() + t += dt + v += dv exp = append(exp, pair{t: t, v: v}) } b.ReportAllocs() b.ResetTimer() - var chunks []Chunk - for i := 0; i < b.N; { + for i := 0; i < b.N; i++ { c := newChunk() a, err := c.Appender() if err != nil { b.Fatalf("get appender: %s", err) } - j := 0 for _, p := range exp { - if j > 250 { - break - } a.Append(p.t, p.v) - i++ - j++ } - chunks = append(chunks, c) } - fmt.Println("num", b.N, "created chunks", len(chunks)) } From b9a9689aae1d366dc0071131b7bbe6d91fb7d2aa Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 18 Sep 2024 10:35:29 +0100 Subject: [PATCH 2/4] [PERF] Chunk encoding: simplify writeByte Rather than append a zero then set the value at that position, append the value. Signed-off-by: Bryan Boreham --- tsdb/chunkenc/bstream.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tsdb/chunkenc/bstream.go b/tsdb/chunkenc/bstream.go index f9668c68c2..6e01798f72 100644 --- a/tsdb/chunkenc/bstream.go +++ b/tsdb/chunkenc/bstream.go @@ -95,10 +95,8 @@ func (b *bstream) writeByte(byt byte) { // Complete the last byte with the leftmost b.count bits from byt. b.stream[i] |= byt >> (8 - b.count) - b.stream = append(b.stream, 0) - i++ // Write the remainder, if any. - b.stream[i] = byt << b.count + b.stream = append(b.stream, byt< Date: Wed, 18 Sep 2024 10:33:44 +0100 Subject: [PATCH 3/4] [PERF] Chunk encoding: combine timestamp writes Instead of a 2-bit write followed by a 14-bit write, do two 8-bit writes, which goes much faster since it avoids looping. Signed-off-by: Bryan Boreham --- tsdb/chunkenc/xor.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tsdb/chunkenc/xor.go b/tsdb/chunkenc/xor.go index ec5db39ad4..ac75a5994b 100644 --- a/tsdb/chunkenc/xor.go +++ b/tsdb/chunkenc/xor.go @@ -191,8 +191,8 @@ func (a *xorAppender) Append(t int64, v float64) { case dod == 0: a.b.writeBit(zero) case bitRange(dod, 14): - a.b.writeBits(0b10, 2) - a.b.writeBits(uint64(dod), 14) + a.b.writeByte(0b10<<6 | (uint8(dod>>8) & (1<<6 - 1))) // 0b10 size code combined with 6 bits of dod. + a.b.writeByte(uint8(dod)) // Bottom 8 bits of dod. case bitRange(dod, 17): a.b.writeBits(0b110, 3) a.b.writeBits(uint64(dod), 17) From e8c2d916eca4f4cd516cbf27fd24c719140cc2b8 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 18 Sep 2024 13:40:44 +0100 Subject: [PATCH 4/4] lint Signed-off-by: Bryan Boreham --- tsdb/chunkenc/chunk_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/tsdb/chunkenc/chunk_test.go b/tsdb/chunkenc/chunk_test.go index 6319db6eec..e6b89be401 100644 --- a/tsdb/chunkenc/chunk_test.go +++ b/tsdb/chunkenc/chunk_test.go @@ -308,5 +308,4 @@ func benchmarkAppender(b *testing.B, deltas func() (int64, float64), newChunk fu a.Append(p.t, p.v) } } - }