mirror of
https://github.com/glebarez/go-sqlite.git
synced 2025-10-06 00:06:56 +08:00
Add simple benchmarks, enable using the new profiling API.
This commit is contained in:
258
all_test.go
258
all_test.go
@@ -7,15 +7,20 @@ package sqlite
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cznic/virtual"
|
||||||
)
|
)
|
||||||
|
|
||||||
func caller(s string, va ...interface{}) {
|
func caller(s string, va ...interface{}) {
|
||||||
@@ -56,7 +61,15 @@ func init() {
|
|||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
func tempDB(t *testing.T) (string, *sql.DB) {
|
var (
|
||||||
|
// -tags virtual.profile
|
||||||
|
profileFunctions = flag.Bool("profile_functions", false, "")
|
||||||
|
profileInstructions = flag.Bool("profile_instructions", false, "")
|
||||||
|
profileLines = flag.Bool("profile_lines", false, "")
|
||||||
|
profileRate = flag.Int("profile_rate", 1000, "")
|
||||||
|
)
|
||||||
|
|
||||||
|
func tempDB(t testing.TB) (string, *sql.DB) {
|
||||||
dir, err := ioutil.TempDir("", "sqlite-test-")
|
dir, err := ioutil.TempDir("", "sqlite-test-")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@@ -73,6 +86,7 @@ func tempDB(t *testing.T) (string, *sql.DB) {
|
|||||||
|
|
||||||
func TestScalar(t *testing.T) {
|
func TestScalar(t *testing.T) {
|
||||||
dir, db := tempDB(t)
|
dir, db := tempDB(t)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
db.Close()
|
db.Close()
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
@@ -140,6 +154,7 @@ func TestScalar(t *testing.T) {
|
|||||||
|
|
||||||
func TestBlob(t *testing.T) {
|
func TestBlob(t *testing.T) {
|
||||||
dir, db := tempDB(t)
|
dir, db := tempDB(t)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
db.Close()
|
db.Close()
|
||||||
os.RemoveAll(dir)
|
os.RemoveAll(dir)
|
||||||
@@ -188,3 +203,244 @@ func TestBlob(t *testing.T) {
|
|||||||
t.Fatal(g, e)
|
t.Fatal(g, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func profile(t testing.TB, d time.Duration, w io.Writer, format string, arg ...interface{}) {
|
||||||
|
rate := vm.ProfileRate
|
||||||
|
if rate == 0 {
|
||||||
|
rate = 1
|
||||||
|
}
|
||||||
|
if len(vm.ProfileFunctions) != 0 {
|
||||||
|
fmt.Fprintf(w, format, arg...)
|
||||||
|
type u struct {
|
||||||
|
virtual.PCInfo
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
var s int64
|
||||||
|
var a []u
|
||||||
|
var wi int
|
||||||
|
for k, v := range vm.ProfileFunctions {
|
||||||
|
a = append(a, u{k, v})
|
||||||
|
s += int64(v)
|
||||||
|
if n := len(k.Name.String()); n > wi {
|
||||||
|
wi = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Slice(a, func(i, j int) bool {
|
||||||
|
if a[i].n < a[j].n {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if a[i].n > a[j].n {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return a[i].Name < a[j].Name
|
||||||
|
})
|
||||||
|
fmt.Fprintf(w, "---- Profile functions, %.3f MIPS\n", float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d))
|
||||||
|
var c int64
|
||||||
|
for i := len(a) - 1; i >= 0; i-- {
|
||||||
|
c += int64(a[i].n)
|
||||||
|
fmt.Fprintf(
|
||||||
|
w,
|
||||||
|
"%*v\t%10v%10.2f%%%10.2f%%\n",
|
||||||
|
-wi, a[i].Name, a[i].n,
|
||||||
|
100*float64(a[i].n)/float64(s),
|
||||||
|
100*float64(c)/float64(s),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(vm.ProfileLines) != 0 {
|
||||||
|
fmt.Fprintf(w, format, arg...)
|
||||||
|
type u struct {
|
||||||
|
virtual.PCInfo
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
var s int64
|
||||||
|
var a []u
|
||||||
|
for k, v := range vm.ProfileLines {
|
||||||
|
a = append(a, u{k, v})
|
||||||
|
s += int64(v)
|
||||||
|
}
|
||||||
|
sort.Slice(a, func(i, j int) bool {
|
||||||
|
if a[i].n < a[j].n {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if a[i].n > a[j].n {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if a[i].Name < a[j].Name {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if a[i].Name > a[j].Name {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return a[i].Line < a[j].Line
|
||||||
|
})
|
||||||
|
fmt.Fprintf(w, "---- Profile lines, %.3f MIPS\n", float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d))
|
||||||
|
var c int64
|
||||||
|
for i := len(a) - 1; i >= 0; i-- {
|
||||||
|
c += int64(a[i].n)
|
||||||
|
fmt.Fprintf(
|
||||||
|
w,
|
||||||
|
"%v:%v:\t%10v%10.2f%%%10.2f%%\n",
|
||||||
|
a[i].Name, a[i].Line, a[i].n,
|
||||||
|
100*float64(a[i].n)/float64(s),
|
||||||
|
100*float64(c)/float64(s),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(vm.ProfileInstructions) != 0 {
|
||||||
|
fmt.Fprintf(w, format, arg...)
|
||||||
|
type u struct {
|
||||||
|
virtual.Opcode
|
||||||
|
n int
|
||||||
|
}
|
||||||
|
var s int64
|
||||||
|
var a []u
|
||||||
|
var wi int
|
||||||
|
for k, v := range vm.ProfileInstructions {
|
||||||
|
a = append(a, u{k, v})
|
||||||
|
s += int64(v)
|
||||||
|
if n := len(k.String()); n > wi {
|
||||||
|
wi = n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort.Slice(a, func(i, j int) bool {
|
||||||
|
if a[i].n < a[j].n {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if a[i].n > a[j].n {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return a[i].Opcode < a[j].Opcode
|
||||||
|
})
|
||||||
|
fmt.Fprintf(w, "---- Profile instructions, %.3f MIPS\n", float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d))
|
||||||
|
var c int64
|
||||||
|
for i := len(a) - 1; i >= 0; i-- {
|
||||||
|
c += int64(a[i].n)
|
||||||
|
fmt.Fprintf(
|
||||||
|
w,
|
||||||
|
"%*s%10v%10.2f%%\t%10.2f%%\n",
|
||||||
|
-wi, a[i].Opcode, a[i].n,
|
||||||
|
100*float64(a[i].n)/float64(s),
|
||||||
|
100*float64(c)/float64(s),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkInsertMemory(b *testing.B) {
|
||||||
|
db, err := sql.Open(driverName, "file::memory:")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
db.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
create table t(i int);
|
||||||
|
begin;
|
||||||
|
`); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := db.Prepare("insert into t values(?)")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if *profileFunctions {
|
||||||
|
vm.ProfileFunctions = map[virtual.PCInfo]int{}
|
||||||
|
}
|
||||||
|
if *profileLines {
|
||||||
|
vm.ProfileLines = map[virtual.PCInfo]int{}
|
||||||
|
}
|
||||||
|
if *profileInstructions {
|
||||||
|
vm.ProfileInstructions = map[virtual.Opcode]int{}
|
||||||
|
}
|
||||||
|
vm.ProfileRate = int(*profileRate)
|
||||||
|
t0 := time.Now()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if _, err := s.Exec(int64(i)); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
d := time.Since(t0)
|
||||||
|
if _, err := db.Exec(`commit;`); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
profile(b, d, os.Stderr, "==== BenchmarkInsertMemory b.N %v\n", b.N)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNextMemory(b *testing.B) {
|
||||||
|
db, err := sql.Open(driverName, "file::memory:")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
db.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
create table t(i int);
|
||||||
|
begin;
|
||||||
|
`); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := db.Prepare("insert into t values(?)")
|
||||||
|
if err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if _, err := s.Exec(int64(i)); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := db.Exec("commit"); err != nil {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, err := db.Query("select * from t")
|
||||||
|
if err != nil {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
if *profileFunctions {
|
||||||
|
vm.ProfileFunctions = map[virtual.PCInfo]int{}
|
||||||
|
}
|
||||||
|
if *profileLines {
|
||||||
|
vm.ProfileLines = map[virtual.PCInfo]int{}
|
||||||
|
}
|
||||||
|
if *profileInstructions {
|
||||||
|
vm.ProfileInstructions = map[virtual.Opcode]int{}
|
||||||
|
}
|
||||||
|
vm.ProfileRate = int(*profileRate)
|
||||||
|
t0 := time.Now()
|
||||||
|
b.ResetTimer()
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if !r.Next() {
|
||||||
|
b.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.StopTimer()
|
||||||
|
d := time.Since(t0)
|
||||||
|
profile(b, d, os.Stderr, "==== BenchmarkNextMemory b.N %v\n", b.N)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user