benchmarks: readability and bugfixes

This commit is contained in:
glebarez
2022-01-11 15:17:31 +01:00
parent 884a3ed642
commit f6f0331b65
5 changed files with 88 additions and 69 deletions

View File

@@ -12,7 +12,7 @@ Additional command line arguments:
| flag | type | default | description |
| ---- | ---- | ------- | ----------------------------------------------------------------------------------------------- |
| -mem | bool | false | if set, use in-memory SQLite |
| -mem | bool | false | if set - benchmarks will use in-memory SQLite instance, otherwise: on-disk instance |
| -rep | uint | 1 | run each benchmark multiple times and average the results. this may provide more stable results |

View File

@@ -1,6 +1,11 @@
// Copyright 2021 The Sqlite Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package benchmark
/* this file contains benchmarks inspired by https://www.sqlite.org/speed.html */
/*
this file contains benchmarks inspired by https://www.sqlite.org/speed.html
*/
import (
"database/sql"
@@ -10,7 +15,7 @@ import (
)
// corresponds to Test 1 from https://www.sqlite.org/speed.html
func bench_insert(b *testing.B, db *sql.DB) {
func benchInsert(b *testing.B, db *sql.DB) {
// create test table
createTestTable(db)
@@ -21,7 +26,7 @@ func bench_insert(b *testing.B, db *sql.DB) {
}
// corresponds to Test 2 from https://www.sqlite.org/speed.html
func bench_insert_in_transaction(b *testing.B, db *sql.DB) {
func benchInsertInTransaction(b *testing.B, db *sql.DB) {
// create test table
createTestTable(db)
@@ -32,7 +37,7 @@ func bench_insert_in_transaction(b *testing.B, db *sql.DB) {
}
// corresponds to Test 3 from https://www.sqlite.org/speed.html
func bench_insert_into_indexed(b *testing.B, db *sql.DB) {
func benchInsertIntoIndexed(b *testing.B, db *sql.DB) {
// create test table with indexed column
createTestTable(db, `c`)
@@ -42,7 +47,7 @@ func bench_insert_into_indexed(b *testing.B, db *sql.DB) {
}
// corresponds to Test 4 from https://www.sqlite.org/speed.html
func bench_select_without_index(b *testing.B, db *sql.DB) {
func benchSelectWithoutIndex(b *testing.B, db *sql.DB) {
// create test table
createTestTable(db)
@@ -66,13 +71,15 @@ func bench_select_without_index(b *testing.B, db *sql.DB) {
// ...
for i := 0; i < b.N; i++ {
b := (i * 100) % maxGeneratedNum
stmt.Exec(b, b+1000)
if _, err := stmt.Exec(b, b+1000); err != nil {
panic(err)
}
}
})
}
// corresponds to Test 5 from https://www.sqlite.org/speed.html
func bench_select_on_string_comparison(b *testing.B, db *sql.DB) {
func benchSelectOnStringComparison(b *testing.B, db *sql.DB) {
// create test table
createTestTable(db)
@@ -105,7 +112,7 @@ func bench_select_on_string_comparison(b *testing.B, db *sql.DB) {
}
// corresponds to Test 6 from https://www.sqlite.org/speed.html
func bench_create_index(b *testing.B, db *sql.DB) {
func benchCreateIndex(b *testing.B, db *sql.DB) {
// create test table
createTestTable(db)
@@ -136,7 +143,7 @@ func bench_create_index(b *testing.B, db *sql.DB) {
}
// corresponds to Test 7 from https://www.sqlite.org/speed.html
func bench_select_with_index(b *testing.B, db *sql.DB) {
func benchSelectWithIndex(b *testing.B, db *sql.DB) {
// create test table with indexed field
createTestTable(db, `b`)
@@ -159,14 +166,17 @@ func bench_select_with_index(b *testing.B, db *sql.DB) {
// SELECT count(*), avg(b) FROM t2 WHERE b>=200 AND b<300;
for i := 0; i < b.N; i++ {
b := (i * 100) % maxGeneratedNum
stmt.Exec(b, b+100)
if _, err := stmt.Exec(b, b+100); err != nil {
panic(err)
}
}
})
}
// corresponds to Test 8 from https://www.sqlite.org/speed.html
func bench_update_without_index(b *testing.B, db *sql.DB) {
func benchUpdateWithoutIndex(b *testing.B, db *sql.DB) {
// create test table
createTestTable(db)
@@ -189,14 +199,16 @@ func bench_update_without_index(b *testing.B, db *sql.DB) {
// UPDATE t1 SET b=b*2 WHERE a>=20 AND a<30;
for i := 0; i < b.N; i++ {
a := (i * 10) % testTableRowCount
stmt.Exec(a, a+10)
if _, err := stmt.Exec(a, a+10); err != nil {
panic(err)
}
}
})
}
// corresponds to Test 9 from https://www.sqlite.org/speed.html
func bench_update_with_index(b *testing.B, db *sql.DB) {
func benchUpdateWithIndex(b *testing.B, db *sql.DB) {
// create test table
createTestTable(db, `a`)
@@ -218,16 +230,18 @@ func bench_update_with_index(b *testing.B, db *sql.DB) {
// UPDATE t2 SET b=121928 WHERE a=2;
// ...
for i := 0; i < b.N; i++ {
stmt.Exec(
if _, err := stmt.Exec(
rand.Uint32(), // b = ?
i%testTableRowCount+1, // WHERE a=?
)
); err != nil {
panic(err)
}
}
})
}
// corresponds to Test 10 from https://www.sqlite.org/speed.html
func bench_update_text_with_index(b *testing.B, db *sql.DB) {
func benchUpdateTextWithIndex(b *testing.B, db *sql.DB) {
// create test table
createTestTable(db, `a`)
@@ -249,16 +263,18 @@ func bench_update_text_with_index(b *testing.B, db *sql.DB) {
// UPDATE t2 SET c='three hundred sixty six thousand five hundred two' WHERE a=2;
for i := 0; i < b.N; i++ {
// generate new random number-as-words for c
stmt.Exec(
if _, err := stmt.Exec(
pronounceNum(uint32(rand.Int31n(maxGeneratedNum))), // SET c=?
i%testTableRowCount+1, // WHERE a=?
)
); err != nil {
panic(err)
}
}
})
}
// corresponds to Test 11 from https://www.sqlite.org/speed.html
func bench_insert_from_select(b *testing.B, db *sql.DB) {
func benchInsertFromSelect(b *testing.B, db *sql.DB) {
// create source table
createTestTable(db)
fillTestTableInTx(db, testTableRowCount)
@@ -292,7 +308,7 @@ func bench_insert_from_select(b *testing.B, db *sql.DB) {
}
// corresponds to Test 12 from https://www.sqlite.org/speed.html
func bench_delete_without_index(b *testing.B, db *sql.DB) {
func benchDeleteWithoutIndex(b *testing.B, db *sql.DB) {
// create test table
createTestTable(db)
@@ -319,7 +335,7 @@ func bench_delete_without_index(b *testing.B, db *sql.DB) {
}
// corresponds to Test 13 from https://www.sqlite.org/speed.html
func bench_delete_with_index(b *testing.B, db *sql.DB) {
func benchDeleteWithIndex(b *testing.B, db *sql.DB) {
// create test table with indexed column
createTestTable(db, `a`)
@@ -346,7 +362,7 @@ func bench_delete_with_index(b *testing.B, db *sql.DB) {
}
// corresponds to Test 16 from https://www.sqlite.org/speed.html
func bench_drop_table(b *testing.B, db *sql.DB) {
func benchDropTable(b *testing.B, db *sql.DB) {
for i := 0; i < b.N; i++ {
b.StopTimer()
createTestTable(db)

View File

@@ -27,22 +27,22 @@ var (
// benchmark funcs to execute
funcs = []func(*testing.B, *sql.DB){
bench_create_index,
bench_select_on_string_comparison,
bench_select_with_index,
bench_select_without_index,
bench_insert,
bench_insert_in_transaction,
bench_insert_into_indexed,
bench_insert_from_select,
bench_update_text_with_index,
bench_update_with_index,
bench_update_without_index,
bench_delete_without_index,
bench_delete_with_index,
benchCreateIndex,
benchSelectOnStringComparison,
benchSelectWithIndex,
benchSelectWithoutIndex,
benchInsert,
benchInsertInTransaction,
benchInsertIntoIndexed,
benchInsertFromSelect,
benchUpdateTextWithIndex,
benchUpdateWithIndex,
benchUpdateWithoutIndex,
benchDeleteWithoutIndex,
benchDeleteWithIndex,
// due to very long run of this benchmark, it is disabled
// bench_drop_table,
// benchDropTable,
}
)
@@ -53,7 +53,7 @@ func TestMain(m *testing.M) {
os.Exit(m.Run())
}
func Test_BenchmarkSQLite(t *testing.T) {
func TestBenchmarkSQLite(t *testing.T) {
// print info about CPU and OS
fmt.Println()
fmt.Printf("goos: %s\n", runtime.GOOS)
@@ -69,8 +69,8 @@ func Test_BenchmarkSQLite(t *testing.T) {
for _, f := range funcs {
var (
nsPerOpBase avgVal
nsPerOp avgVal
nsPerOpCGo avgVal
nsPerOpPureGo avgVal
)
// run benchmark against different drivers
@@ -80,7 +80,7 @@ func Test_BenchmarkSQLite(t *testing.T) {
br := testing.Benchmark(func(b *testing.B) { f(b, db) })
// contribue metric to average
nsPerOpBase.contribInt(br.NsPerOp())
nsPerOpCGo.contribInt(br.NsPerOp())
// close DB
if err := db.Close(); err != nil {
@@ -92,7 +92,7 @@ func Test_BenchmarkSQLite(t *testing.T) {
br = testing.Benchmark(func(b *testing.B) { f(b, db) })
// contribue metric to average
nsPerOp.contribInt(br.NsPerOp())
nsPerOpPureGo.contribInt(br.NsPerOp())
// close DB
if err := db.Close(); err != nil {
t.Fatal(err)
@@ -101,10 +101,10 @@ func Test_BenchmarkSQLite(t *testing.T) {
// print result row
fmt.Printf("%-35s | %5.2fx | CGo: %7.3f ms/op | Pure-Go: %7.3f ms/op\n",
getFuncName(f),
nsPerOp.val/nsPerOpBase.val,
nsPerOpBase.val/1e6,
nsPerOp.val/1e6,
toSnakeCase(getFuncName(f)),
nsPerOpPureGo.val/nsPerOpCGo.val, // factor
nsPerOpCGo.val/1e6, // ms/op
nsPerOpPureGo.val/1e6, // ms/op
)
}
}

View File

@@ -10,6 +10,7 @@ import (
"math/rand"
"path"
"reflect"
"regexp"
"runtime"
"strings"
"testing"
@@ -26,6 +27,17 @@ const (
testTableName = "t1"
)
var (
matchFirstCap = regexp.MustCompile("(.)([A-Z][a-z]+)")
matchAllCap = regexp.MustCompile("([a-z0-9])([A-Z])")
)
func toSnakeCase(str string) string {
snake := matchFirstCap.ReplaceAllString(str, "${1}_${2}")
snake = matchAllCap.ReplaceAllString(snake, "${1}_${2}")
return strings.ToLower(snake)
}
// mustExec executes SQL statements and panic if error occurs
func mustExec(db *sql.DB, statements ...string) {
for _, s := range statements {
@@ -133,14 +145,16 @@ func createDB(tb testing.TB, inMemory bool, driverName string) *sql.DB {
}
db.SetMaxOpenConns(1)
// if !inMemory {
// // disable sync
// _, err = db.Exec(`PRAGMA synchronous = OFF`)
// if err != nil {
// tb.Fatal(err)
// }
// }
// when in on-disk mode - set synchronous = OFF
// this turns off fsync() sys call at every record inserted out of transaction scope
// thus we don't bother HDD/SSD too often during specific bechmarks
if !inMemory {
// disable sync
_, err = db.Exec(`PRAGMA synchronous = OFF`)
if err != nil {
tb.Fatal(err)
}
}
return db
}
@@ -193,11 +207,6 @@ func pronounceNum(n uint32) string {
panic("must have returned already")
}
// fracDiv does a fractional division of 2 integers
func fracDiv(x, y int64) float64 {
return float64(x) / float64(y)
}
// AvgVal provides average value with value contributions on-the-fly
type avgVal struct {
// the current average value
@@ -208,7 +217,9 @@ type avgVal struct {
}
func (a *avgVal) contribFloat(v float64) {
a.val = (a.val*float64(a.numContributions) + v) / (float64(a.numContributions) + 1.)
nContrib := float64(a.numContributions)
a.val = (a.val*nContrib + v) / (nContrib + 1.)
a.numContributions++
}
func (a *avgVal) contribInt(v int64) {

View File

@@ -9,15 +9,7 @@ import (
"testing"
)
func test_pronounceNum(t *testing.T) {
// this is only for visual testing
for i := 0; i < 10; i++ {
n := rand.Int31()
t.Logf("%d: %s\n", n, pronounceNum(uint32(n)))
}
}
func Benchmark_pronounceNum(b *testing.B) {
func BenchmarkPronounceNum(b *testing.B) {
for i := 0; i < b.N; i++ {
n := rand.Int31()
pronounceNum(uint32(n))