diff --git a/benchmark.go b/benchmark.go index 9253842..ab5bc17 100644 --- a/benchmark.go +++ b/benchmark.go @@ -3,6 +3,8 @@ package main import ( "sync" "time" + + log "github.com/sirupsen/logrus" ) // Benchmark to store benchmark state @@ -42,6 +44,7 @@ func (b *Benchmark) Run() { // Queries returns the number of executed queries during the benchmark func (b *Benchmark) Queries() (queries float64) { for _, database := range b.databases { + log.Debugf("Connection %s: Queries: %.f", database.ID, database.Queries()) queries = queries + database.Queries() } return @@ -51,3 +54,14 @@ func (b *Benchmark) Queries() (queries float64) { func (b *Benchmark) QueriesPerSecond() float64 { return b.Queries() / b.duration.Seconds() } + +// AverageQueryTime computes the average query execution time for all databases connections in the benchmark +func (b *Benchmark) AverageQueryTime() time.Duration { + var latencies time.Duration + for _, database := range b.databases { + log.Debugf("Connection %s: Latency: %s", database.ID, database.AverageQueryTime()) + latencies = latencies + database.AverageQueryTime() + } + latency := int64(latencies) / int64(len(b.databases)) + return time.Duration(latency) +} diff --git a/config.go b/config.go index 6872ba2..c6230a1 100644 --- a/config.go +++ b/config.go @@ -97,14 +97,15 @@ func (c *Config) parsePostgresDSN() string { func (c *Config) parseMysqlDSN() (dsn string) { config := mysql.NewConfig() + config.Timeout = 1 * time.Second config.Addr = c.Host if c.Port != 0 { + config.Net = "tcp" config.Addr += fmt.Sprintf(":%d", c.Port) } config.User = c.User config.Passwd = c.Password config.DBName = c.Database config.TLSConfig = c.TLS - return config.FormatDSN() } diff --git a/database.go b/database.go index 844f6f3..319c465 100644 --- a/database.go +++ b/database.go @@ -2,19 +2,27 @@ package main import ( "database/sql" - "log" "sync" "time" + + "github.com/google/uuid" + log "github.com/sirupsen/logrus" ) // Database to store a single connection to the database and its statistics type Database struct { + ID uuid.UUID db *sql.DB driver string dsn string query string reconnect bool - queries float64 + + queries float64 // Total number of queries + queriesLock *sync.Mutex + + queriesDuration time.Duration // Time spent executing queries + queriesDurationLock *sync.Mutex } // NewDatabase creates a single connection to the database then returns the struct @@ -29,6 +37,9 @@ func NewDatabase(driver string, dsn string, query string, reconnect bool) (*Data if err != nil { return nil, err } + database.ID = uuid.New() + database.queriesLock = &sync.Mutex{} + database.queriesDurationLock = &sync.Mutex{} return database, nil } @@ -63,6 +74,7 @@ func (d *Database) Run(duration time.Duration, wg *sync.WaitGroup) error { if end.Before(time.Now()) { break } + queryStart := time.Now() result, err := d.db.Query(d.query) if err != nil { log.Fatalf("Failed query the database: %v", err) @@ -71,7 +83,20 @@ func (d *Database) Run(duration time.Duration, wg *sync.WaitGroup) error { log.Fatalf("Failed to close query: %v", err) } + queryDuration := time.Now().Sub(queryStart) + + // Update statistics + d.queriesLock.Lock() d.queries++ + d.queriesLock.Unlock() + + d.queriesDurationLock.Lock() + d.queriesDuration = d.queriesDuration + queryDuration + d.queriesDurationLock.Unlock() + + // Print debug statistics + log.Debugf("Connection %s: Number of queries: %.f | Query duration: %s | Running sum of queries duration: %s", d.ID, d.queries, queryDuration, d.queriesDuration) + if d.reconnect { if err = d.disconnect(); err != nil { return err @@ -89,3 +114,8 @@ func (d *Database) Run(duration time.Duration, wg *sync.WaitGroup) error { func (d *Database) Queries() float64 { return d.queries } + +// AverageQueryTime returns the average query execution time in milliseconds +func (d *Database) AverageQueryTime() time.Duration { + return d.queriesDuration / time.Duration(d.queries) +} diff --git a/go.mod b/go.mod index 75e1b51..f184cfd 100644 --- a/go.mod +++ b/go.mod @@ -7,9 +7,10 @@ require ( github.com/lib/pq v1.10.7 ) -require gopkg.in/yaml.v2 v2.4.0 - require ( - github.com/sirupsen/logrus v1.9.0 // indirect - golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect + github.com/google/uuid v1.3.0 + github.com/sirupsen/logrus v1.9.0 + gopkg.in/yaml.v2 v2.4.0 ) + +require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect diff --git a/go.sum b/go.sum index c96922f..3f57846 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,18 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -15,4 +20,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 9558971..eba286f 100644 --- a/main.go +++ b/main.go @@ -83,6 +83,8 @@ func main() { benchmark.Run() fmt.Printf("Queries: %.0f\n", benchmark.Queries()) fmt.Printf("Queries per second: %.0f\n", benchmark.QueriesPerSecond()) + fmt.Printf("Average query time: %s\n", benchmark.AverageQueryTime()) + fmt.Printf("Average query time (ms): %d\n", benchmark.AverageQueryTime().Milliseconds()) } func showVersion() {