Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
173 changes: 173 additions & 0 deletions benchmark_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

package mysql

import (
"bytes"
"database/sql"
"strings"
"sync"
"sync/atomic"
"testing"
)

type TB testing.B

func (tb *TB) check(err error) {
if err != nil {
tb.Fatal(err)
}
}

func (tb *TB) checkDB(db *sql.DB, err error) *sql.DB {
tb.check(err)
return db
}

func (tb *TB) checkRows(rows *sql.Rows, err error) *sql.Rows {
tb.check(err)
return rows
}

func (tb *TB) checkStmt(stmt *sql.Stmt, err error) *sql.Stmt {
tb.check(err)
return stmt
}

func initDB(b *testing.B, queries ...string) *sql.DB {
tb := (*TB)(b)
db := tb.checkDB(sql.Open("mysql", dsn))
for _, query := range queries {
if _, err := db.Exec(query); err != nil {
b.Fatalf("Error on %q: %v", query, err)
}
}
return db
}

// by Brad Fitzpatrick
const concurrencyLevel = 10

func BenchmarkQuery(b *testing.B) {
tb := (*TB)(b)
b.StopTimer()
b.ReportAllocs()
db := initDB(b,
"DROP TABLE IF EXISTS foo",
"CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))",
`INSERT INTO foo VALUES (1, "one")`,
`INSERT INTO foo VALUES (2, "two")`,
)
db.SetMaxIdleConns(concurrencyLevel)
defer db.Close()

stmt := tb.checkStmt(db.Prepare("SELECT val FROM foo WHERE id=?"))
defer stmt.Close()
b.StartTimer()

remain := int64(b.N)
var wg sync.WaitGroup
wg.Add(concurrencyLevel)
defer wg.Wait()
for i := 0; i < concurrencyLevel; i++ {
go func() {
defer wg.Done()
for {
if atomic.AddInt64(&remain, -1) < 0 {
return
}
var got string
tb.check(stmt.QueryRow(1).Scan(&got))
if got != "one" {
b.Errorf("query = %q; want one", got)
return
}
}
}()
}
}

// data, but no db writes
var roundtripSample []byte

func initRoundtripBenchmarks() ([]byte, int, int) {
if roundtripSample == nil {
roundtripSample = []byte(strings.Repeat("0123456789abcdef", 1024*1024))
}
return roundtripSample, 16, len(roundtripSample)
}

func BenchmarkRoundtripTxt(b *testing.B) {
b.StopTimer()
sample, min, max := initRoundtripBenchmarks()
sampleString := string(sample)
b.ReportAllocs()
tb := (*TB)(b)
db := tb.checkDB(sql.Open("mysql", dsn))
defer db.Close()
b.StartTimer()
var result string
for i := 0; i < b.N; i++ {
length := min + i
if length > max {
length = max
}
test := sampleString[0:length]
rows := tb.checkRows(db.Query(`SELECT "` + test + `"`))
if !rows.Next() {
rows.Close()
b.Fatalf("crashed")
}
err := rows.Scan(&result)
if err != nil {
rows.Close()
b.Fatalf("crashed")
}
if result != test {
rows.Close()
b.Errorf("mismatch")
}
rows.Close()
}
}

func BenchmarkRoundtripBin(b *testing.B) {
b.StopTimer()
sample, min, max := initRoundtripBenchmarks()
b.ReportAllocs()
tb := (*TB)(b)
db := tb.checkDB(sql.Open("mysql", dsn))
defer db.Close()
stmt := tb.checkStmt(db.Prepare("SELECT ?"))
defer stmt.Close()
b.StartTimer()
var result sql.RawBytes
for i := 0; i < b.N; i++ {
length := min + i
if length > max {
length = max
}
test := sample[0:length]
rows := tb.checkRows(stmt.Query(test))
if !rows.Next() {
rows.Close()
b.Fatalf("crashed")
}
err := rows.Scan(&result)
if err != nil {
rows.Close()
b.Fatalf("crashed")
}
if !bytes.Equal(result, test) {
rows.Close()
b.Errorf("mismatch")
}
rows.Close()
}
}
84 changes: 0 additions & 84 deletions driver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1150,87 +1150,3 @@ func TestConcurrent(t *testing.T) {
dbt.Logf("Reached %d concurrent connections \r\n", max)
})
}

// BENCHMARKS
var sample []byte

func initBenchmarks() ([]byte, int, int) {
if sample == nil {
sample = []byte(strings.Repeat("0123456789abcdef", 1024*1024))
}
return sample, 16, len(sample)
}

func BenchmarkRoundtripText(b *testing.B) {
sample, min, max := initBenchmarks()
db, err := sql.Open("mysql", dsn)
if err != nil {
b.Fatalf("crashed")
}
defer db.Close()
var result string
for i := 0; i < b.N; i++ {
length := min + i
if length > max {
length = max
}
test := string(sample[0:length])
rows, err := db.Query("SELECT \"" + test + "\"")
if err != nil {
b.Fatalf("crashed")
}
if !rows.Next() {
rows.Close()
b.Fatalf("crashed")
}
err = rows.Scan(&result)
if err != nil {
rows.Close()
b.Fatalf("crashed")
}
if result != test {
rows.Close()
b.Errorf("mismatch")
}
rows.Close()
}
}

func BenchmarkRoundtripPrepared(b *testing.B) {
sample, min, max := initBenchmarks()
db, err := sql.Open("mysql", dsn)
if err != nil {
b.Fatalf("crashed")
}
defer db.Close()
var result string
stmt, err := db.Prepare("SELECT ?")
if err != nil {
b.Fatalf("crashed")
}
for i := 0; i < b.N; i++ {
length := min + i
if length > max {
length = max
}
test := string(sample[0:length])
rows, err := stmt.Query(test)
if err != nil {
b.Fatalf("crashed")
}
if !rows.Next() {
rows.Close()
b.Fatalf("crashed")
}
err = rows.Scan(&result)
if err != nil {
rows.Close()
b.Fatalf("crashed")
}
if result != test {
rows.Close()
b.Errorf("mismatch")
}
rows.Close()
}
}