github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/database/mysql/benchmark_test.go (about) 1 // Go MySQL Driver - A MySQL-Driver for Go's database/sql package 2 // 3 // Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved. 4 // 5 // This Source Code Form is subject to the terms of the Mozilla Public 6 // License, v. 2.0. If a copy of the MPL was not distributed with this file, 7 // You can obtain one at http://mozilla.org/MPL/2.0/. 8 9 package mysql 10 11 import ( 12 "bytes" 13 "database/sql" 14 "strings" 15 "sync" 16 "sync/atomic" 17 "testing" 18 ) 19 20 type TB testing.B 21 22 func (tb *TB) check(err error) { 23 if err != nil { 24 tb.Fatal(err) 25 } 26 } 27 28 func (tb *TB) checkDB(db *sql.DB, err error) *sql.DB { 29 tb.check(err) 30 return db 31 } 32 33 func (tb *TB) checkRows(rows *sql.Rows, err error) *sql.Rows { 34 tb.check(err) 35 return rows 36 } 37 38 func (tb *TB) checkStmt(stmt *sql.Stmt, err error) *sql.Stmt { 39 tb.check(err) 40 return stmt 41 } 42 43 func initDB(b *testing.B, queries ...string) *sql.DB { 44 tb := (*TB)(b) 45 db := tb.checkDB(sql.Open("mysql", dsn)) 46 for _, query := range queries { 47 if _, err := db.Exec(query); err != nil { 48 b.Fatalf("Error on %q: %v", query, err) 49 } 50 } 51 return db 52 } 53 54 const concurrencyLevel = 10 55 56 func BenchmarkQuery(b *testing.B) { 57 tb := (*TB)(b) 58 b.StopTimer() 59 b.ReportAllocs() 60 db := initDB(b, 61 "DROP TABLE IF EXISTS foo", 62 "CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))", 63 `INSERT INTO foo VALUES (1, "one")`, 64 `INSERT INTO foo VALUES (2, "two")`, 65 ) 66 db.SetMaxIdleConns(concurrencyLevel) 67 defer db.Close() 68 69 stmt := tb.checkStmt(db.Prepare("SELECT val FROM foo WHERE id=?")) 70 defer stmt.Close() 71 72 remain := int64(b.N) 73 var wg sync.WaitGroup 74 wg.Add(concurrencyLevel) 75 defer wg.Wait() 76 b.StartTimer() 77 78 for i := 0; i < concurrencyLevel; i++ { 79 go func() { 80 for { 81 if atomic.AddInt64(&remain, -1) < 0 { 82 wg.Done() 83 return 84 } 85 86 var got string 87 tb.check(stmt.QueryRow(1).Scan(&got)) 88 if got != "one" { 89 b.Errorf("query = %q; want one", got) 90 wg.Done() 91 return 92 } 93 } 94 }() 95 } 96 } 97 98 func BenchmarkExec(b *testing.B) { 99 tb := (*TB)(b) 100 b.StopTimer() 101 b.ReportAllocs() 102 db := tb.checkDB(sql.Open("mysql", dsn)) 103 db.SetMaxIdleConns(concurrencyLevel) 104 defer db.Close() 105 106 stmt := tb.checkStmt(db.Prepare("DO 1")) 107 defer stmt.Close() 108 109 remain := int64(b.N) 110 var wg sync.WaitGroup 111 wg.Add(concurrencyLevel) 112 defer wg.Wait() 113 b.StartTimer() 114 115 for i := 0; i < concurrencyLevel; i++ { 116 go func() { 117 for { 118 if atomic.AddInt64(&remain, -1) < 0 { 119 wg.Done() 120 return 121 } 122 123 if _, err := stmt.Exec(); err != nil { 124 b.Fatal(err.Error()) 125 } 126 } 127 }() 128 } 129 } 130 131 // data, but no db writes 132 var roundtripSample []byte 133 134 func initRoundtripBenchmarks() ([]byte, int, int) { 135 if roundtripSample == nil { 136 roundtripSample = []byte(strings.Repeat("0123456789abcdef", 1024*1024)) 137 } 138 return roundtripSample, 16, len(roundtripSample) 139 } 140 141 func BenchmarkRoundtripTxt(b *testing.B) { 142 b.StopTimer() 143 sample, min, max := initRoundtripBenchmarks() 144 sampleString := string(sample) 145 b.ReportAllocs() 146 tb := (*TB)(b) 147 db := tb.checkDB(sql.Open("mysql", dsn)) 148 defer db.Close() 149 b.StartTimer() 150 var result string 151 for i := 0; i < b.N; i++ { 152 length := min + i 153 if length > max { 154 length = max 155 } 156 test := sampleString[0:length] 157 rows := tb.checkRows(db.Query(`SELECT "` + test + `"`)) 158 if !rows.Next() { 159 rows.Close() 160 b.Fatalf("crashed") 161 } 162 err := rows.Scan(&result) 163 if err != nil { 164 rows.Close() 165 b.Fatalf("crashed") 166 } 167 if result != test { 168 rows.Close() 169 b.Errorf("mismatch") 170 } 171 rows.Close() 172 } 173 } 174 175 func BenchmarkRoundtripBin(b *testing.B) { 176 b.StopTimer() 177 sample, min, max := initRoundtripBenchmarks() 178 b.ReportAllocs() 179 tb := (*TB)(b) 180 db := tb.checkDB(sql.Open("mysql", dsn)) 181 defer db.Close() 182 stmt := tb.checkStmt(db.Prepare("SELECT ?")) 183 defer stmt.Close() 184 b.StartTimer() 185 var result sql.RawBytes 186 for i := 0; i < b.N; i++ { 187 length := min + i 188 if length > max { 189 length = max 190 } 191 test := sample[0:length] 192 rows := tb.checkRows(stmt.Query(test)) 193 if !rows.Next() { 194 rows.Close() 195 b.Fatalf("crashed") 196 } 197 err := rows.Scan(&result) 198 if err != nil { 199 rows.Close() 200 b.Fatalf("crashed") 201 } 202 if !bytes.Equal(result, test) { 203 rows.Close() 204 b.Errorf("mismatch") 205 } 206 rows.Close() 207 } 208 }