113 lines
3 KiB
Go
113 lines
3 KiB
Go
|
package postgresql
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"math/rand"
|
||
|
"strconv"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/stretchr/testify/require"
|
||
|
|
||
|
"github.com/influxdata/telegraf"
|
||
|
"github.com/influxdata/telegraf/config"
|
||
|
"github.com/influxdata/telegraf/metric"
|
||
|
)
|
||
|
|
||
|
func BenchmarkPostgresql_sequential(b *testing.B) {
|
||
|
gen := batchGenerator(batchGeneratorArgs{ctx, b, 1000, 3, 8, 12, 100, 2})
|
||
|
benchmarkPostgresql(b, gen, 1, true)
|
||
|
}
|
||
|
func BenchmarkPostgresql_concurrent(b *testing.B) {
|
||
|
gen := batchGenerator(batchGeneratorArgs{ctx, b, 1000, 3, 8, 12, 100, 2})
|
||
|
benchmarkPostgresql(b, gen, 10, true)
|
||
|
}
|
||
|
|
||
|
func benchmarkPostgresql(b *testing.B, gen <-chan []telegraf.Metric, concurrency int, foreignTags bool) {
|
||
|
p, err := newPostgresqlTest(b)
|
||
|
require.NoError(b, err)
|
||
|
|
||
|
connection, err := p.Connection.Get()
|
||
|
require.NoError(b, err)
|
||
|
p.Connection = config.NewSecret([]byte(connection.String() + fmt.Sprintf(" pool_max_conns=%d", concurrency)))
|
||
|
connection.Destroy()
|
||
|
|
||
|
p.TagsAsForeignKeys = foreignTags
|
||
|
p.LogLevel = ""
|
||
|
require.NoError(b, p.Init())
|
||
|
if err := p.Connect(); err != nil {
|
||
|
b.Fatalf("Error: %s", err)
|
||
|
}
|
||
|
|
||
|
metricCount := 0
|
||
|
|
||
|
b.ResetTimer()
|
||
|
tStart := time.Now()
|
||
|
for i := 0; i < b.N; i++ {
|
||
|
batch := <-gen
|
||
|
if err := p.Write(batch); err != nil {
|
||
|
b.Fatalf("Error: %s", err)
|
||
|
}
|
||
|
metricCount += len(batch)
|
||
|
}
|
||
|
_ = p.Close()
|
||
|
b.StopTimer()
|
||
|
tStop := time.Now()
|
||
|
b.ReportMetric(float64(metricCount)/tStop.Sub(tStart).Seconds(), "metrics/s")
|
||
|
}
|
||
|
|
||
|
type batchGeneratorArgs struct {
|
||
|
ctx context.Context
|
||
|
b *testing.B
|
||
|
batchSize int
|
||
|
numTables int
|
||
|
numTags int
|
||
|
numFields int
|
||
|
tagCardinality int
|
||
|
fieldCardinality int
|
||
|
}
|
||
|
|
||
|
// tagCardinality counts all the tag keys & values as one element. fieldCardinality counts all the field keys (not values) as one element.
|
||
|
func batchGenerator(args batchGeneratorArgs) <-chan []telegraf.Metric {
|
||
|
tagSets := make([]MSS, 0, args.tagCardinality)
|
||
|
for i := 0; i < args.tagCardinality; i++ {
|
||
|
tags := MSS{}
|
||
|
for j := 0; j < args.numTags; j++ {
|
||
|
tags[fmt.Sprintf("tag_%d", j)] = strconv.Itoa(rand.Int())
|
||
|
}
|
||
|
tagSets = append(tagSets, tags)
|
||
|
}
|
||
|
|
||
|
metricChan := make(chan []telegraf.Metric, 32)
|
||
|
go func() {
|
||
|
for {
|
||
|
batch := make([]telegraf.Metric, 0, args.batchSize)
|
||
|
for i := 0; i < args.batchSize; i++ {
|
||
|
tableName := args.b.Name() + "_" + strconv.Itoa(rand.Intn(args.numTables))
|
||
|
|
||
|
tags := tagSets[rand.Intn(len(tagSets))]
|
||
|
|
||
|
m := metric.New(tableName, tags, nil, time.Now())
|
||
|
m.AddTag("tableName", tableName) // ensure the tag set is unique to this table. Just in case...
|
||
|
|
||
|
// We do field cardinality by randomizing the name of the final field to an integer < cardinality.
|
||
|
for j := 0; j < args.numFields-1; j++ { // use -1 to reserve the last field for cardinality
|
||
|
m.AddField("f"+strconv.Itoa(j), rand.Int())
|
||
|
}
|
||
|
m.AddField("f"+strconv.Itoa(rand.Intn(args.fieldCardinality)), rand.Int())
|
||
|
|
||
|
batch = append(batch, m)
|
||
|
}
|
||
|
|
||
|
select {
|
||
|
case metricChan <- batch:
|
||
|
case <-ctx.Done():
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
}()
|
||
|
|
||
|
return metricChan
|
||
|
}
|