chore(tsm1): Add benchmarks for existing typed decoders

These benchmarks will be implemented in batched decoders to compare
performance.
pull/10084/head
Stuart Carnie 2018-07-02 16:55:01 -07:00
parent 75e0bca597
commit 7948a8e217
7 changed files with 681 additions and 88 deletions

View File

@ -0,0 +1,105 @@
package testutil
import (
"math/rand"
"strings"
)
// MakeSentence returns a string made up of n words.
// MakeSentence uses rand.Int31n and therefore calling rand.Seed will produce
// deterministic results.
func MakeSentence(n int) string {
s := make([]string, n)
for i := 0; i < n; i++ {
s[i] = words[rand.Int31n(int32(len(words)))]
}
return strings.Join(s, " ")
}
var words = [...]string{
"lorem", "ipsum", "dolor", "sit", "amet", "consectetuer", "adipiscing", "elit", "integer", "in", "mi", "a", "mauris",
"ornare", "sagittis", "suspendisse", "potenti", "suspendisse", "dapibus", "dignissim", "dolor", "nam",
"sapien", "tellus", "tempus", "et", "tempus", "ac", "tincidunt", "in", "arcu", "duis", "dictum", "proin", "magna",
"nulla", "pellentesque", "non", "commodo", "et", "iaculis", "sit", "amet", "mi", "mauris", "condimentum", "massa",
"ut", "metus", "donec", "viverra", "sapien", "mattis", "rutrum", "tristique", "lacus", "eros", "semper", "tellus",
"et", "molestie", "nisi", "sapien", "eu", "massa", "vestibulum", "ante", "ipsum", "primis", "in", "faucibus", "orci",
"luctus", "et", "ultrices", "posuere", "cubilia", "curae", "fusce", "erat", "tortor", "mollis", "ut", "accumsan",
"ut", "lacinia", "gravida", "libero", "curabitur", "massa", "felis", "accumsan", "feugiat", "convallis", "sit",
"amet", "porta", "vel", "neque", "duis", "et", "ligula", "non", "elit", "ultricies", "rutrum", "suspendisse",
"tempor", "quisque", "posuere", "malesuada", "velit", "sed", "pellentesque", "mi", "a", "purus", "integer",
"imperdiet", "orci", "a", "eleifend", "mollis", "velit", "nulla", "iaculis", "arcu", "eu", "rutrum", "magna", "quam",
"sed", "elit", "nullam", "egestas", "integer", "interdum", "purus", "nec", "mauris", "vestibulum", "ac", "mi", "in",
"nunc", "suscipit", "dapibus", "duis", "consectetuer", "ipsum", "et", "pharetra", "sollicitudin", "metus",
"turpis", "facilisis", "magna", "vitae", "dictum", "ligula", "nulla", "nec", "mi", "nunc", "ante", "urna", "gravida",
"sit", "amet", "congue", "et", "accumsan", "vitae", "magna", "praesent", "luctus", "nullam", "in", "velit",
"praesent", "est", "curabitur", "turpis", "class", "aptent", "taciti", "sociosqu", "ad", "litora", "torquent",
"per", "conubia", "nostra", "per", "inceptos", "hymenaeos", "cras", "consectetuer", "nibh", "in", "lacinia",
"ornare", "turpis", "sem", "tempor", "massa", "sagittis", "feugiat", "mauris", "nibh", "non", "tellus",
"phasellus", "mi", "fusce", "enim", "mauris", "ultrices", "turpis", "eu", "adipiscing", "viverra", "justo",
"libero", "ullamcorper", "massa", "id", "ultrices", "velit", "est", "quis", "tortor", "quisque", "condimentum",
"lacus", "volutpat", "nonummy", "accumsan", "est", "nunc", "imperdiet", "magna", "vulputate", "aliquet", "nisi",
"risus", "at", "est", "aliquam", "imperdiet", "gravida", "tortor", "praesent", "interdum", "accumsan", "ante",
"vivamus", "est", "ligula", "consequat", "sed", "pulvinar", "eu", "consequat", "vitae", "eros", "nulla", "elit",
"nunc", "congue", "eget", "scelerisque", "a", "tempor", "ac", "nisi", "morbi", "facilisis", "pellentesque",
"habitant", "morbi", "tristique", "senectus", "et", "netus", "et", "malesuada", "fames", "ac", "turpis", "egestas",
"in", "hac", "habitasse", "platea", "dictumst", "suspendisse", "vel", "lorem", "ut", "ligula", "tempor",
"consequat", "quisque", "consectetuer", "nisl", "eget", "elit", "proin", "quis", "mauris", "ac", "orci",
"accumsan", "suscipit", "sed", "ipsum", "sed", "vel", "libero", "nec", "elit", "feugiat", "blandit", "vestibulum",
"purus", "nulla", "accumsan", "et", "volutpat", "at", "pellentesque", "vel", "urna", "suspendisse", "nonummy",
"aliquam", "pulvinar", "libero", "donec", "vulputate", "orci", "ornare", "bibendum", "condimentum", "lorem",
"elit", "dignissim", "sapien", "ut", "aliquam", "nibh", "augue", "in", "turpis", "phasellus", "ac", "eros",
"praesent", "luctus", "lorem", "a", "mollis", "lacinia", "leo", "turpis", "commodo", "sem", "in", "lacinia", "mi",
"quam", "et", "quam", "curabitur", "a", "libero", "vel", "tellus", "mattis", "imperdiet", "in", "congue", "neque", "ut",
"scelerisque", "bibendum", "libero", "lacus", "ullamcorper", "sapien", "quis", "aliquet", "massa", "velit",
"vel", "orci", "fusce", "in", "nulla", "quis", "est", "cursus", "gravida", "in", "nibh", "lorem", "ipsum", "dolor", "sit",
"amet", "consectetuer", "adipiscing", "elit", "integer", "fermentum", "pretium", "massa", "morbi", "feugiat",
"iaculis", "nunc", "aenean", "aliquam", "pretium", "orci", "cum", "sociis", "natoque", "penatibus", "et", "magnis",
"dis", "parturient", "montes", "nascetur", "ridiculus", "mus", "vivamus", "quis", "tellus", "vel", "quam",
"varius", "bibendum", "fusce", "est", "metus", "feugiat", "at", "porttitor", "et", "cursus", "quis", "pede", "nam", "ut",
"augue", "nulla", "posuere", "phasellus", "at", "dolor", "a", "enim", "cursus", "vestibulum", "duis", "id", "nisi",
"duis", "semper", "tellus", "ac", "nulla", "vestibulum", "scelerisque", "lobortis", "dolor", "aenean", "a",
"felis", "aliquam", "erat", "volutpat", "donec", "a", "magna", "vitae", "pede", "sagittis", "lacinia", "cras",
"vestibulum", "diam", "ut", "arcu", "mauris", "a", "nunc", "duis", "sollicitudin", "erat", "sit", "amet", "turpis",
"proin", "at", "libero", "eu", "diam", "lobortis", "fermentum", "nunc", "lorem", "turpis", "imperdiet", "id",
"gravida", "eget", "aliquet", "sed", "purus", "ut", "vehicula", "laoreet", "ante", "mauris", "eu", "nunc", "sed", "sit",
"amet", "elit", "nec", "ipsum", "aliquam", "egestas", "donec", "non", "nibh", "cras", "sodales", "pretium", "massa",
"praesent", "hendrerit", "est", "et", "risus", "vivamus", "eget", "pede", "curabitur", "tristique",
"scelerisque", "dui", "nullam", "ullamcorper", "vivamus", "venenatis", "velit", "eget", "enim", "nunc", "eu",
"nunc", "eget", "felis", "malesuada", "fermentum", "quisque", "magna", "mauris", "ligula", "felis", "luctus", "a",
"aliquet", "nec", "vulputate", "eget", "magna", "quisque", "placerat", "diam", "sed", "arcu", "praesent",
"sollicitudin", "aliquam", "non", "sapien", "quisque", "id", "augue", "class", "aptent", "taciti", "sociosqu",
"ad", "litora", "torquent", "per", "conubia", "nostra", "per", "inceptos", "hymenaeos", "etiam", "lacus", "lectus",
"mollis", "quis", "mattis", "nec", "commodo", "facilisis", "nibh", "sed", "sodales", "sapien", "ac", "ante", "duis",
"eget", "lectus", "in", "nibh", "lacinia", "auctor", "fusce", "interdum", "lectus", "non", "dui", "integer",
"accumsan", "quisque", "quam", "curabitur", "scelerisque", "imperdiet", "nisl", "suspendisse", "potenti",
"nam", "massa", "leo", "iaculis", "sed", "accumsan", "id", "ultrices", "nec", "velit", "suspendisse", "potenti",
"mauris", "bibendum", "turpis", "ac", "viverra", "sollicitudin", "metus", "massa", "interdum", "orci", "non",
"imperdiet", "orci", "ante", "at", "ipsum", "etiam", "eget", "magna", "mauris", "at", "tortor", "eu", "lectus",
"tempor", "tincidunt", "phasellus", "justo", "purus", "pharetra", "ut", "ultricies", "nec", "consequat", "vel",
"nisi", "fusce", "vitae", "velit", "at", "libero", "sollicitudin", "sodales", "aenean", "mi", "libero", "ultrices",
"id", "suscipit", "vitae", "dapibus", "eu", "metus", "aenean", "vestibulum", "nibh", "ac", "massa", "vivamus",
"vestibulum", "libero", "vitae", "purus", "in", "hac", "habitasse", "platea", "dictumst", "curabitur",
"blandit", "nunc", "non", "arcu", "ut", "nec", "nibh", "morbi", "quis", "leo", "vel", "magna", "commodo", "rhoncus",
"donec", "congue", "leo", "eu", "lacus", "pellentesque", "at", "erat", "id", "mi", "consequat", "congue", "praesent",
"a", "nisl", "ut", "diam", "interdum", "molestie", "fusce", "suscipit", "rhoncus", "sem", "donec", "pretium",
"aliquam", "molestie", "vivamus", "et", "justo", "at", "augue", "aliquet", "dapibus", "pellentesque", "felis",
"morbi", "semper", "in", "venenatis", "imperdiet", "neque", "donec", "auctor", "molestie", "augue", "nulla", "id",
"arcu", "sit", "amet", "dui", "lacinia", "convallis", "proin", "tincidunt", "proin", "a", "ante", "nunc", "imperdiet",
"augue", "nullam", "sit", "amet", "arcu", "quisque", "laoreet", "viverra", "felis", "lorem", "ipsum", "dolor", "sit",
"amet", "consectetuer", "adipiscing", "elit", "in", "hac", "habitasse", "platea", "dictumst", "pellentesque",
"habitant", "morbi", "tristique", "senectus", "et", "netus", "et", "malesuada", "fames", "ac", "turpis", "egestas",
"class", "aptent", "taciti", "sociosqu", "ad", "litora", "torquent", "per", "conubia", "nostra", "per", "inceptos",
"hymenaeos", "nullam", "nibh", "sapien", "volutpat", "ut", "placerat", "quis", "ornare", "at", "lorem", "class",
"aptent", "taciti", "sociosqu", "ad", "litora", "torquent", "per", "conubia", "nostra", "per", "inceptos",
"hymenaeos", "morbi", "dictum", "massa", "id", "libero", "ut", "neque", "phasellus", "tincidunt", "nibh", "ut",
"tincidunt", "lacinia", "lacus", "nulla", "aliquam", "mi", "a", "interdum", "dui", "augue", "non", "pede", "duis",
"nunc", "magna", "vulputate", "a", "porta", "at", "tincidunt", "a", "nulla", "praesent", "facilisis",
"suspendisse", "sodales", "feugiat", "purus", "cras", "et", "justo", "a", "mauris", "mollis", "imperdiet", "morbi",
"erat", "mi", "ultrices", "eget", "aliquam", "elementum", "iaculis", "id", "velit", "in", "scelerisque", "enim",
"sit", "amet", "turpis", "sed", "aliquam", "odio", "nonummy", "ullamcorper", "mollis", "lacus", "nibh", "tempor",
"dolor", "sit", "amet", "varius", "sem", "neque", "ac", "dui", "nunc", "et", "est", "eu", "massa", "eleifend", "mollis",
"mauris", "aliquet", "orci", "quis", "tellus", "ut", "mattis", "praesent", "mollis", "consectetuer", "quam",
"nulla", "nulla", "nunc", "accumsan", "nunc", "sit", "amet", "scelerisque", "porttitor", "nibh", "pede", "lacinia",
"justo", "tristique", "mattis", "purus", "eros", "non", "velit", "aenean", "sagittis", "commodo", "erat",
"aliquam", "id", "lacus", "morbi", "vulputate", "vestibulum", "elit",
}

View File

@ -1,6 +1,7 @@
package tsm1_test
import (
"fmt"
"reflect"
"testing"
"testing/quick"
@ -131,31 +132,44 @@ func Test_BooleanDecoder_Corrupt(t *testing.T) {
}
}
func BenchmarkBooleanDecoder_2048(b *testing.B) { benchmarkBooleanDecoder(b, 2048) }
func benchmarkBooleanDecoder(b *testing.B, size int) {
e := tsm1.NewBooleanEncoder(size)
for i := 0; i < size; i++ {
e.Write(i&1 == 1)
}
bytes, err := e.Bytes()
if err != nil {
b.Fatalf("unexpected error: %v", err)
func BenchmarkBooleanDecoder_DecodeAll(b *testing.B) {
benchmarks := []struct {
n int
}{
{1},
{55},
{555},
{1000},
}
for _, bm := range benchmarks {
b.Run(fmt.Sprintf("%d", bm.n), func(b *testing.B) {
size := bm.n
e := tsm1.NewBooleanEncoder(size)
for i := 0; i < size; i++ {
e.Write(i&1 == 1)
}
bytes, err := e.Bytes()
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
b.ResetTimer()
b.SetBytes(int64(len(bytes)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
var d tsm1.BooleanDecoder
d.SetBytes(bytes)
dst := make([]bool, size)
for i := 0; i < b.N; i++ {
var d tsm1.BooleanDecoder
d.SetBytes(bytes)
var n int
for d.Next() {
_ = d.Read()
n++
}
if n != size {
b.Fatalf("expected to read %d booleans, but read %d", size, n)
}
var n int
for d.Next() {
dst[n] = d.Read()
n++
}
if n != size {
b.Fatalf("expected to read %d booleans, but read %d", size, n)
}
}
})
}
}

View File

@ -2,6 +2,7 @@ package tsm1_test
import (
"fmt"
"math/rand"
"reflect"
"testing"
"time"
@ -1470,6 +1471,175 @@ func BenchmarkDecodeBlock_Boolean_TypeSpecific(b *testing.B) {
}
}
func BenchmarkDecodeBooleanBlock(b *testing.B) {
cases := []int{
5,
55,
555,
1000,
}
for _, n := range cases {
b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
valueCount := n
times := getTimes(valueCount, 60, time.Second)
values := make([]tsm1.Value, len(times))
for i, t := range times {
values[i] = tsm1.NewValue(t, true)
}
bytes, err := tsm1.Values(values).Encode(nil)
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
b.ResetTimer()
b.ReportAllocs()
b.SetBytes(int64(tsm1.Values(values).Size()))
b.RunParallel(func(pb *testing.PB) {
decodedValues := make([]tsm1.BooleanValue, len(values))
for pb.Next() {
_, err = tsm1.DecodeBooleanBlock(bytes, &decodedValues)
if err != nil {
b.Fatalf("unexpected error decoding block: %v", err)
}
}
})
})
}
}
func BenchmarkDecodeFloatBlock(b *testing.B) {
cases := []int{
5,
55,
555,
1000,
}
for _, n := range cases {
b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
valueCount := n
times := getTimes(valueCount, 60, time.Second)
values := make([]tsm1.Value, len(times))
for i, t := range times {
values[i] = tsm1.NewValue(t, float64(i))
}
bytes, err := tsm1.Values(values).Encode(nil)
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
b.ResetTimer()
b.ReportAllocs()
b.SetBytes(int64(tsm1.Values(values).Size()))
b.RunParallel(func(pb *testing.PB) {
decodedValues := make([]tsm1.FloatValue, len(values))
for pb.Next() {
_, err = tsm1.DecodeFloatBlock(bytes, &decodedValues)
if err != nil {
b.Fatalf("unexpected error decoding block: %v", err)
}
}
})
})
}
}
func BenchmarkDecodeIntegerBlock(b *testing.B) {
rle := func(i int) int64 { return int64(i) }
s8b := func(i int) int64 { return int64(i + int(rand.Int31n(10))) }
cases := []struct {
enc string
gen func(i int) int64
n int
}{
{enc: "rle", gen: rle, n: 5},
{enc: "rle", gen: rle, n: 55},
{enc: "rle", gen: rle, n: 555},
{enc: "rle", gen: rle, n: 1000},
{enc: "s8b", gen: s8b, n: 5},
{enc: "s8b", gen: s8b, n: 55},
{enc: "s8b", gen: s8b, n: 555},
{enc: "s8b", gen: s8b, n: 1000},
}
for _, bm := range cases {
b.Run(fmt.Sprintf("%s_%d", bm.enc, bm.n), func(b *testing.B) {
rand.Seed(int64(bm.n * 1e3))
valueCount := bm.n
times := getTimes(valueCount, 60, time.Second)
values := make([]tsm1.Value, len(times))
for i, t := range times {
values[i] = tsm1.NewValue(t, bm.gen(i))
}
bytes, err := tsm1.Values(values).Encode(nil)
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
b.ResetTimer()
b.ReportAllocs()
b.SetBytes(int64(tsm1.Values(values).Size()))
b.RunParallel(func(pb *testing.PB) {
decodedValues := make([]tsm1.IntegerValue, len(values))
for pb.Next() {
_, err = tsm1.DecodeIntegerBlock(bytes, &decodedValues)
if err != nil {
b.Fatalf("unexpected error decoding block: %v", err)
}
}
})
})
}
}
func BenchmarkDecodeStringBlock(b *testing.B) {
cases := []int{
5,
55,
555,
1000,
}
for _, n := range cases {
b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
valueCount := n
times := getTimes(valueCount, 60, time.Second)
values := make([]tsm1.Value, len(times))
for i, t := range times {
values[i] = tsm1.NewValue(t, fmt.Sprintf("value %d", i))
}
bytes, err := tsm1.Values(values).Encode(nil)
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
b.ResetTimer()
b.ReportAllocs()
b.SetBytes(int64(tsm1.Values(values).Size()))
b.RunParallel(func(pb *testing.PB) {
decodedValues := make([]tsm1.StringValue, len(values))
for pb.Next() {
_, err = tsm1.DecodeStringBlock(bytes, &decodedValues)
if err != nil {
b.Fatalf("unexpected error decoding block: %v", err)
}
}
})
})
}
}
func BenchmarkDecodeBlock_String_Empty(b *testing.B) {
valueCount := 1000
times := getTimes(valueCount, 60, time.Second)

View File

@ -1,11 +1,13 @@
package tsm1_test
import (
"fmt"
"math"
"reflect"
"testing"
"testing/quick"
"github.com/google/go-cmp/cmp"
"github.com/influxdata/influxdb/tsdb/engine/tsm1"
)
@ -118,40 +120,26 @@ func TestFloatEncoder_SimilarFloats(t *testing.T) {
}
}
var TwoHoursData = []struct {
v float64
}{
// 2h of data
{761}, {727}, {763}, {706}, {700},
{679}, {757}, {708}, {739}, {707},
{699}, {740}, {729}, {766}, {730},
{715}, {705}, {693}, {765}, {724},
{799}, {761}, {737}, {766}, {756},
{719}, {722}, {801}, {747}, {731},
{742}, {744}, {791}, {750}, {759},
{809}, {751}, {705}, {770}, {792},
{727}, {762}, {772}, {721}, {748},
{753}, {744}, {716}, {776}, {659},
{789}, {766}, {758}, {690}, {795},
{770}, {758}, {723}, {767}, {765},
{693}, {706}, {681}, {727}, {724},
{780}, {678}, {696}, {758}, {740},
{735}, {700}, {742}, {747}, {752},
{734}, {743}, {732}, {746}, {770},
{780}, {710}, {731}, {712}, {712},
{741}, {770}, {770}, {754}, {718},
{670}, {775}, {749}, {795}, {756},
{741}, {787}, {721}, {745}, {782},
{765}, {780}, {811}, {790}, {836},
{743}, {858}, {739}, {762}, {770},
{752}, {763}, {795}, {792}, {746},
{786}, {785}, {774}, {786}, {718},
var twoHoursData = []float64{
// 2h of data, rows of 10 values
761, 727, 763, 706, 700, 679, 757, 708, 739, 707,
699, 740, 729, 766, 730, 715, 705, 693, 765, 724,
799, 761, 737, 766, 756, 719, 722, 801, 747, 731,
742, 744, 791, 750, 759, 809, 751, 705, 770, 792,
727, 762, 772, 721, 748, 753, 744, 716, 776, 659,
789, 766, 758, 690, 795, 770, 758, 723, 767, 765,
693, 706, 681, 727, 724, 780, 678, 696, 758, 740,
735, 700, 742, 747, 752, 734, 743, 732, 746, 770,
780, 710, 731, 712, 712, 741, 770, 770, 754, 718,
670, 775, 749, 795, 756, 741, 787, 721, 745, 782,
765, 780, 811, 790, 836, 743, 858, 739, 762, 770,
752, 763, 795, 792, 746, 786, 785, 774, 786, 718,
}
func TestFloatEncoder_Roundtrip(t *testing.T) {
s := tsm1.NewFloatEncoder()
for _, p := range TwoHoursData {
s.Write(p.v)
for _, p := range twoHoursData {
s.Write(p)
}
s.Flush()
@ -165,14 +153,14 @@ func TestFloatEncoder_Roundtrip(t *testing.T) {
t.Fatalf("unexpected error creating float decoder: %v", err)
}
for _, w := range TwoHoursData {
for _, w := range twoHoursData {
if !it.Next() {
t.Fatalf("Next()=false, want true")
}
vv := it.Values()
// t.Logf("it.Values()=(%+v, %+v)\n", time.Unix(int64(tt), 0), vv)
if w.v != vv {
t.Errorf("Values()=(%v), want (%v)\n", vv, w.v)
if w != vv {
t.Errorf("Values()=(%v), want (%v)\n", vv, w)
}
}
@ -253,8 +241,8 @@ func TestFloatDecoder_Empty(t *testing.T) {
func BenchmarkFloatEncoder(b *testing.B) {
for i := 0; i < b.N; i++ {
s := tsm1.NewFloatEncoder()
for _, tt := range TwoHoursData {
s.Write(tt.v)
for _, tt := range twoHoursData {
s.Write(tt)
}
s.Flush()
}
@ -262,8 +250,8 @@ func BenchmarkFloatEncoder(b *testing.B) {
func BenchmarkFloatDecoder(b *testing.B) {
s := tsm1.NewFloatEncoder()
for _, tt := range TwoHoursData {
s.Write(tt.v)
for _, tt := range twoHoursData {
s.Write(tt)
}
s.Flush()
bytes, err := s.Bytes()
@ -279,8 +267,53 @@ func BenchmarkFloatDecoder(b *testing.B) {
b.Fatalf("unexpected error creating float decoder: %v", err)
}
for j := 0; j < len(TwoHoursData); it.Next() {
for j := 0; j < len(twoHoursData); it.Next() {
j++
}
}
}
func BenchmarkFloatDecoder_DecodeAll(b *testing.B) {
benchmarks := []struct {
n int
}{
{1},
{55},
{550},
{1000},
}
for _, bm := range benchmarks {
b.Run(fmt.Sprintf("%d", bm.n), func(b *testing.B) {
s := tsm1.NewFloatEncoder()
for c := 0; c < bm.n; c++ {
s.Write(twoHoursData[c%len(twoHoursData)])
}
s.Flush()
bytes, err := s.Bytes()
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
dst := make([]float64, bm.n)
b.SetBytes(int64(len(bytes)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
var it tsm1.FloatDecoder
if err := it.SetBytes(bytes); err != nil {
b.Fatalf("unexpected error creating float decoder: %v", err)
}
i := 0
for it.Next() {
dst[i] = it.Values()
i++
}
if len(dst) != bm.n {
b.Fatalf("unexpected length -got/+exp\n%s", cmp.Diff(len(dst), bm.n))
}
}
})
}
}

View File

@ -1,6 +1,7 @@
package tsm1
import (
"fmt"
"math"
"math/rand"
"reflect"
@ -604,43 +605,130 @@ func BenchmarkIntegerEncoderPackedSimple(b *testing.B) {
}
}
func BenchmarkIntegerDecoderPackedSimple(b *testing.B) {
x := make([]int64, 1024)
enc := NewIntegerEncoder(1024)
for i := 0; i < len(x); i++ {
// Small amount of randomness prevents RLE from being used
x[i] = int64(i) + int64(rand.Intn(10))
enc.Write(x[i])
func BenchmarkIntegerBatch_DecodeAllUncompressed(b *testing.B) {
benchmarks := []struct {
n int
}{
{5},
{55},
{555},
{1000},
}
bytes, _ := enc.Bytes()
b.ResetTimer()
values := []int64{
-2352281900722994752, 1438442655375607923, -4110452567888190110,
-1221292455668011702, -1941700286034261841, -2836753127140407751,
1432686216250034552, 3663244026151507025, -3068113732684750258,
-1949953187327444488, 3713374280993588804, 3226153669854871355,
-2093273755080502606, 1006087192578600616, -2272122301622271655,
2533238229511593671, -4450454445568858273, 2647789901083530435,
2761419461769776844, -1324397441074946198, -680758138988210958,
94468846694902125, -2394093124890745254, -2682139311758778198,
}
var dec IntegerDecoder
for i := 0; i < b.N; i++ {
dec.SetBytes(bytes)
for dec.Next() {
}
for _, bm := range benchmarks {
b.Run(fmt.Sprintf("%d", bm.n), func(b *testing.B) {
rand.Seed(int64(bm.n * 1e3))
enc := NewIntegerEncoder(bm.n)
for i := 0; i < bm.n; i++ {
enc.Write(values[rand.Int()%len(values)])
}
bytes, _ := enc.Bytes()
dst := make([]int64, bm.n)
b.SetBytes(int64(len(bytes)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
var dec IntegerDecoder
dec.SetBytes(bytes)
var n int
for dec.Next() {
dst[n] = dec.Read()
n++
}
}
})
}
}
func BenchmarkIntegerDecoderRLE(b *testing.B) {
x := make([]int64, 1024)
enc := NewIntegerEncoder(1024)
for i := 0; i < len(x); i++ {
x[i] = int64(i)
enc.Write(x[i])
func BenchmarkIntegerBatch_DecodeAllPackedSimple(b *testing.B) {
benchmarks := []struct {
n int
}{
{5},
{55},
{555},
{1000},
}
bytes, _ := enc.Bytes()
for _, bm := range benchmarks {
b.Run(fmt.Sprintf("%d", bm.n), func(b *testing.B) {
rand.Seed(int64(bm.n * 1e3))
b.ResetTimer()
enc := NewIntegerEncoder(bm.n)
for i := 0; i < bm.n; i++ {
// Small amount of randomness prevents RLE from being used
enc.Write(int64(i) + int64(rand.Intn(10)))
}
bytes, _ := enc.Bytes()
var dec IntegerDecoder
dec.SetBytes(bytes)
dst := make([]int64, bm.n)
for i := 0; i < b.N; i++ {
dec.SetBytes(bytes)
for dec.Next() {
}
b.SetBytes(int64(len(bytes)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
var dec IntegerDecoder
dec.SetBytes(bytes)
var n int
for dec.Next() {
dst[n] = dec.Read()
n++
}
}
})
}
}
func BenchmarkIntegerBatch_DecodeAllRLE(b *testing.B) {
benchmarks := []struct {
n int
delta int64
}{
{5, 1},
{55, 1},
{555, 1},
{1000, 1},
{1000, 0},
}
for _, bm := range benchmarks {
b.Run(fmt.Sprintf("%d_delta_%d", bm.n, bm.delta), func(b *testing.B) {
enc := NewIntegerEncoder(bm.n)
acc := int64(0)
for i := 0; i < bm.n; i++ {
enc.Write(acc)
acc += bm.delta
}
bytes, _ := enc.Bytes()
b.SetBytes(int64(len(bytes)))
b.ReportAllocs()
b.ResetTimer()
dst := make([]int64, bm.n)
for i := 0; i < b.N; i++ {
var dec IntegerDecoder
dec.SetBytes(bytes)
var n int
for dec.Next() {
dst[n] = dec.Read()
n++
}
}
})
}
}

View File

@ -2,9 +2,13 @@ package tsm1
import (
"fmt"
"math/rand"
"reflect"
"testing"
"testing/quick"
"github.com/google/go-cmp/cmp"
"github.com/influxdata/influxdb/internal/testutil"
)
func Test_StringEncoder_NoValues(t *testing.T) {
@ -175,3 +179,52 @@ func Test_StringDecoder_CorruptSetBytes(t *testing.T) {
}
}
}
func BenchmarkStringDecoder_DecodeAll(b *testing.B) {
benchmarks := []struct {
n int
w int
}{
{1, 10},
{55, 10},
{550, 10},
{1000, 10},
}
for _, bm := range benchmarks {
b.Run(fmt.Sprintf("%d", bm.n), func(b *testing.B) {
rand.Seed(int64(bm.n * 1e3))
s := NewStringEncoder(bm.n)
for c := 0; c < bm.n; c++ {
s.Write(testutil.MakeSentence(bm.w))
}
s.Flush()
bytes, err := s.Bytes()
if err != nil {
b.Fatalf("unexpected error: %v", err)
}
dst := make([]string, bm.n)
b.ReportAllocs()
b.SetBytes(int64(len(bytes)))
b.ResetTimer()
for i := 0; i < b.N; i++ {
var it StringDecoder
if err := it.SetBytes(bytes); err != nil {
b.Fatalf("unexpected error creating float decoder: %v", err)
}
i := 0
for it.Next() {
dst[i] = it.Read()
i++
}
if len(dst) != bm.n {
b.Fatalf("unexpected length -got/+exp\n%s", cmp.Diff(len(dst), bm.n))
}
}
})
}
}

View File

@ -1,6 +1,8 @@
package tsm1
import (
"fmt"
"math/rand"
"reflect"
"testing"
"testing/quick"
@ -602,3 +604,131 @@ func BenchmarkTimeDecoder_RLE(b *testing.B) {
}
}
}
func BenchmarkTimeBatch_DecodeAllUncompressed(b *testing.B) {
benchmarks := []struct {
n int
}{
{5},
{55},
{555},
{1000},
}
values := []int64{
-2352281900722994752, 1438442655375607923, -4110452567888190110,
-1221292455668011702, -1941700286034261841, -2836753127140407751,
1432686216250034552, 3663244026151507025, -3068113732684750258,
-1949953187327444488, 3713374280993588804, 3226153669854871355,
-2093273755080502606, 1006087192578600616, -2272122301622271655,
2533238229511593671, -4450454445568858273, 2647789901083530435,
2761419461769776844, -1324397441074946198, -680758138988210958,
94468846694902125, -2394093124890745254, -2682139311758778198,
}
for _, bm := range benchmarks {
b.Run(fmt.Sprintf("%d", bm.n), func(b *testing.B) {
rand.Seed(int64(bm.n * 1e3))
enc := NewTimeEncoder(bm.n)
for i := 0; i < bm.n; i++ {
enc.Write(values[rand.Int()%len(values)])
}
bytes, _ := enc.Bytes()
dst := make([]int64, bm.n)
b.SetBytes(int64(len(bytes)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
var dec TimeDecoder
dec.Init(bytes)
var n int
for dec.Next() {
dst[n] = dec.Read()
n++
}
}
})
}
}
func BenchmarkTimeBatch_DecodeAllPackedSimple(b *testing.B) {
benchmarks := []struct {
n int
}{
{5},
{55},
{555},
{1000},
}
for _, bm := range benchmarks {
b.Run(fmt.Sprintf("%d", bm.n), func(b *testing.B) {
rand.Seed(int64(bm.n * 1e3))
enc := NewTimeEncoder(bm.n)
for i := 0; i < bm.n; i++ {
// Small amount of randomness prevents RLE from being used
enc.Write(int64(i*1000) + int64(rand.Intn(10)))
}
bytes, _ := enc.Bytes()
dst := make([]int64, bm.n)
b.SetBytes(int64(len(bytes)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
var dec TimeDecoder
dec.Init(bytes)
var n int
for dec.Next() {
dst[n] = dec.Read()
n++
}
}
})
}
}
func BenchmarkTimeBatch_DecodeAllRLE(b *testing.B) {
benchmarks := []struct {
n int
delta int64
}{
{5, 10},
{55, 10},
{555, 10},
{1000, 10},
}
for _, bm := range benchmarks {
b.Run(fmt.Sprintf("%d_delta_%d", bm.n, bm.delta), func(b *testing.B) {
enc := NewTimeEncoder(bm.n)
acc := int64(0)
for i := 0; i < bm.n; i++ {
enc.Write(acc)
acc += bm.delta
}
bytes, _ := enc.Bytes()
dst := make([]int64, bm.n)
b.SetBytes(int64(len(bytes)))
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
var dec TimeDecoder
dec.Init(bytes)
var n int
for dec.Next() {
dst[n] = dec.Read()
n++
}
}
})
}
}