switch windows to CRT, throw out old virtual

This commit is contained in:
Steffen
2017-06-10 14:02:32 +02:00
parent 212e4e19af
commit 6b30b8701e
9 changed files with 339513 additions and 2281 deletions

View File

@@ -1,494 +0,0 @@
// Copyright 2017 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 sqlite
import (
"bytes"
"database/sql"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"path/filepath"
"runtime"
"sort"
"strings"
"testing"
"time"
"github.com/cznic/virtual"
)
func caller(s string, va ...interface{}) {
if s == "" {
s = strings.Repeat("%v ", len(va))
}
_, fn, fl, _ := runtime.Caller(2)
fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl)
fmt.Fprintf(os.Stderr, s, va...)
fmt.Fprintln(os.Stderr)
_, fn, fl, _ = runtime.Caller(1)
fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl)
fmt.Fprintln(os.Stderr)
os.Stderr.Sync()
}
func dbg(s string, va ...interface{}) {
if s == "" {
s = strings.Repeat("%v ", len(va))
}
_, fn, fl, _ := runtime.Caller(1)
fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl)
fmt.Fprintf(os.Stderr, s, va...)
fmt.Fprintln(os.Stderr)
os.Stderr.Sync()
}
func TODO(...interface{}) string { //TODOOK
_, fn, fl, _ := runtime.Caller(1)
return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK
}
func use(...interface{}) {}
func init() {
use(caller, dbg, TODO) //TODOOK
}
// ============================================================================
var (
// Add "-tags virtual.profile" to the command.
profileAll = flag.Bool("profile", false, "")
profileFunctions = flag.Bool("profile_functions", false, "")
profileInstructions = flag.Bool("profile_instructions", false, "")
profileLines = flag.Bool("profile_lines", false, "")
profileRate = flag.Int("profile_rate", 1000, "")
recsPerSec = flag.Bool("recs_per_sec_as_mbps", false, "Show records per second as MB/s.")
)
func tempDB(t testing.TB) (string, *sql.DB) {
dir, err := ioutil.TempDir("", "sqlite-test-")
if err != nil {
t.Fatal(err)
}
db, err := sql.Open(driverName, filepath.Join(dir, "tmp.db"))
if err != nil {
os.RemoveAll(dir)
t.Fatal(err)
}
return dir, db
}
func TestScalar(t *testing.T) {
dir, db := tempDB(t)
defer func() {
db.Close()
os.RemoveAll(dir)
}()
t1 := time.Date(2017, 4, 20, 1, 2, 3, 56789, time.UTC)
t2 := time.Date(2018, 5, 21, 2, 3, 4, 98765, time.UTC)
r, err := db.Exec(`
create table t(i int, f double, b bool, s text, t time);
insert into t values(12, 3.14, ?, "foo", ?), (34, 2.78, ?, "bar", ?);
`,
true, t1,
false, t2,
)
if err != nil {
t.Fatal(err)
}
n, err := r.RowsAffected()
if err != nil {
t.Fatal(err)
}
if g, e := n, int64(2); g != e {
t.Fatal(g, e)
}
rows, err := db.Query("select * from t")
if err != nil {
t.Fatal(err)
}
type rec struct {
i int
f float64
b bool
s string
t string
}
var a []rec
for rows.Next() {
var r rec
if err := rows.Scan(&r.i, &r.f, &r.b, &r.s, &r.t); err != nil {
t.Fatal(err)
}
a = append(a, r)
}
if err := rows.Err(); err != nil {
t.Fatal(err)
}
if g, e := len(a), 2; g != e {
t.Fatal(g, e)
}
if g, e := a[0], (rec{12, 3.14, true, "foo", t1.String()}); g != e {
t.Fatal(g, e)
}
if g, e := a[1], (rec{34, 2.78, false, "bar", t2.String()}); g != e {
t.Fatal(g, e)
}
}
func TestBlob(t *testing.T) {
dir, db := tempDB(t)
defer func() {
db.Close()
os.RemoveAll(dir)
}()
b1 := []byte(time.Now().String())
b2 := []byte("\x00foo\x00bar\x00")
if _, err := db.Exec(`
create table t(b blob);
insert into t values(?), (?);
`, b1, b2,
); err != nil {
t.Fatal(err)
}
rows, err := db.Query("select * from t")
if err != nil {
t.Fatal(err)
}
type rec struct {
b []byte
}
var a []rec
for rows.Next() {
var r rec
if err := rows.Scan(&r.b); err != nil {
t.Fatal(err)
}
a = append(a, r)
}
if err := rows.Err(); err != nil {
t.Fatal(err)
}
if g, e := len(a), 2; g != e {
t.Fatal(g, e)
}
if g, e := a[0].b, b1; !bytes.Equal(g, e) {
t.Fatal(g, e)
}
if g, e := a[1].b, b2; !bytes.Equal(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)+len(vm.ProfileLines)+len(vm.ProfileInstructions) != 0 {
fmt.Fprintf(w, "# %v\n", os.Args[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, %v samples in %v, %.3f MIPS, %v/sample\n", s, d, float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d), time.Duration(float64(d)/float64(s)))
if x, ok := t.(*testing.B); ok {
fmt.Fprintf(w, "\t%v samples/1 [samples/b.N]\n", s/int64(x.N))
}
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, %v samples in %v, %.3f MIPS, %v/sample\n", s, d, float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d), time.Duration(float64(d)/float64(s)))
if x, ok := t.(*testing.B); ok {
fmt.Fprintf(w, "\t%v samples/1 [samples/b.N]\n", s/int64(x.N))
}
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, %v samples in %v, %.3f MIPS, %v/sample\n", s, d, float64(s)/1e6*float64(rate)*float64(time.Second)/float64(d), time.Duration(float64(d)/float64(s)))
if x, ok := t.(*testing.B); ok {
fmt.Fprintf(w, "\t%v samples/1 [samples/b.N]\n", s/int64(x.N))
}
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 *profileAll || *profileFunctions {
vm.ProfileFunctions = map[virtual.PCInfo]int{}
}
if *profileAll || *profileLines {
vm.ProfileLines = map[virtual.PCInfo]int{}
}
if *profileAll || *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()
if *recsPerSec {
b.SetBytes(1e6)
}
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 *profileAll || *profileFunctions {
vm.ProfileFunctions = map[virtual.PCInfo]int{}
}
if *profileAll || *profileLines {
vm.ProfileLines = map[virtual.PCInfo]int{}
}
if *profileAll || *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()
if *recsPerSec {
b.SetBytes(1e6)
}
d := time.Since(t0)
profile(b, d, os.Stderr, "==== BenchmarkNextMemory b.N %v\n", b.N)
}
// https://github.com/cznic/sqlite/issues/11
func TestIssue11(t *testing.T) {
const N = 6570
dir, db := tempDB(t)
defer func() {
db.Close()
os.RemoveAll(dir)
}()
if _, err := db.Exec(`
CREATE TABLE t1 (t INT);
BEGIN;
`,
); err != nil {
panic(err)
}
for i := 0; i < N; i++ {
if _, err := db.Exec("INSERT INTO t1 (t) VALUES (?)", i); err != nil {
t.Fatalf("#%v: %v", i, err)
}
}
if _, err := db.Exec("COMMIT;"); err != nil {
t.Fatal(err)
}
}

View File

@@ -1,7 +0,0 @@
// Copyright 2017 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.
//go:generate go run generator_windows.go
package sqlite

View File

@@ -168,6 +168,7 @@ func build(predef string, tus [][]string, opts ...cc.Opt) ([]*cc.TranslationUnit
cc.EnableEmptyStructs(), cc.EnableEmptyStructs(),
cc.EnableImplicitFuncDef(), cc.EnableImplicitFuncDef(),
cc.EnableNonConstStaticInitExpressions(), cc.EnableNonConstStaticInitExpressions(),
cc.EnableWideBitFieldTypes(),
cc.ErrLimit(*errLimit), cc.ErrLimit(*errLimit),
cc.SysIncludePaths([]string{ccir.LibcIncludePath}), cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
}, opts...)..., }, opts...)...,

View File

@@ -1,366 +0,0 @@
// Copyright 2017 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.
// +build ignore
package main
import (
"bytes"
"compress/gzip"
"encoding/gob"
"flag"
"fmt"
"go/format"
"go/scanner"
"go/token"
"io"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"sort"
"strings"
"log"
"github.com/cznic/cc"
"github.com/cznic/ccir"
"github.com/cznic/internal/buffer"
"github.com/cznic/ir"
"github.com/cznic/strutil"
"github.com/cznic/virtual"
"github.com/cznic/xc"
)
var (
cpp = flag.Bool("cpp", false, "")
dict = xc.Dict
errLimit = flag.Int("errlimit", 10, "")
filter = flag.String("re", "", "")
ndebug = flag.Bool("ndebug", false, "")
noexec = flag.Bool("noexec", false, "")
oLog = flag.Bool("log", false, "")
trace = flag.Bool("trc", false, "")
yydebug = flag.Int("yydebug", 0, "")
)
func findRepo(s string) string {
s = filepath.FromSlash(s)
for _, v := range strings.Split(strutil.Gopath(), string(os.PathListSeparator)) {
p := filepath.Join(v, "src", s)
fi, err := os.Lstat(p)
if err != nil {
continue
}
if fi.IsDir() {
wd, err := os.Getwd()
if err != nil {
log.Fatal(err)
}
if p, err = filepath.Rel(wd, p); err != nil {
log.Fatal(err)
}
return p
}
}
return ""
}
func errStr(err error) string {
switch x := err.(type) {
case scanner.ErrorList:
if len(x) != 1 {
x.RemoveMultiples()
}
var b bytes.Buffer
for i, v := range x {
if i != 0 {
b.WriteByte('\n')
}
b.WriteString(v.Error())
if i == 9 {
fmt.Fprintf(&b, "\n\t... and %v more errors", len(x)-10)
break
}
}
return b.String()
default:
return err.Error()
}
}
func build(predef string, tus [][]string, opts ...cc.Opt) ([]*cc.TranslationUnit, *virtual.Binary) {
var b buffer.Bytes
var lpos token.Position
if *cpp {
opts = append(opts, cc.Cpp(func(toks []xc.Token) {
if len(toks) != 0 {
p := toks[0].Position()
if p.Filename != lpos.Filename {
fmt.Fprintf(&b, "# %d %q\n", p.Line, p.Filename)
}
lpos = p
}
for _, v := range toks {
b.WriteString(cc.TokSrc(v))
}
b.WriteByte('\n')
}))
}
ndbg := ""
if *ndebug {
ndbg = "#define NDEBUG 1"
}
var build [][]ir.Object
tus = append(tus, []string{ccir.CRT0Path})
var asta []*cc.TranslationUnit
for _, src := range tus {
model, err := ccir.NewModel()
if err != nil {
log.Fatal(err)
}
ast, err := cc.Parse(
fmt.Sprintf(`
%s
#define __arch__ %s
#define __os__ %s
#include <builtin.h>
%s
`, ndbg, runtime.GOARCH, runtime.GOOS, predef),
src,
model,
append([]cc.Opt{
cc.AllowCompatibleTypedefRedefinitions(),
cc.EnableImplicitFuncDef(),
cc.EnableNonConstStaticInitExpressions(),
cc.EnableWideBitFieldTypes(),
cc.ErrLimit(*errLimit),
cc.SysIncludePaths([]string{ccir.LibcIncludePath}),
}, opts...)...,
)
if s := b.Bytes(); len(s) != 0 {
log.Printf("\n%s", s)
b.Close()
}
if err != nil {
log.Fatal(errStr(err))
}
asta = append(asta, ast)
objs, err := ccir.New(ast)
if err != nil {
log.Fatal(err)
}
if *oLog {
for i, v := range objs {
switch x := v.(type) {
case *ir.DataDefinition:
fmt.Fprintf(&b, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Value)
case *ir.FunctionDefinition:
fmt.Fprintf(&b, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
for i, v := range x.Body {
fmt.Fprintf(&b, "%#05x\t%v\n", i, v)
}
default:
log.Fatalf("[%v]: %T %v: %v", i, x, x, err)
}
}
}
for i, v := range objs {
if err := v.Verify(); err != nil {
switch x := v.(type) {
case *ir.FunctionDefinition:
fmt.Fprintf(&b, "# [%v, err]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments)
for i, v := range x.Body {
fmt.Fprintf(&b, "%#05x\t%v\n", i, v)
}
log.Fatalf("# [%v]: Verify (A): %v\n%s", i, err, b.Bytes())
default:
log.Fatalf("[%v]: %T %v: %v", i, x, x, err)
}
}
}
build = append(build, objs)
}
linked, err := ir.LinkMain(build...)
if err != nil {
log.Fatalf("ir.LinkMain: %s\n%s", err, b.Bytes())
}
for _, v := range linked {
if err := v.Verify(); err != nil {
log.Fatal(err)
}
}
bin, err := virtual.LoadMain(linked)
if err != nil {
log.Fatal(err)
}
return asta, bin
}
func macros(buf io.Writer, ast *cc.TranslationUnit) {
var a []string
for k, v := range ast.Macros {
if v.Value != nil && v.Type.Kind() != cc.Bool {
switch fn := v.DefTok.Position().Filename; {
case
fn == "builtin.h",
fn == "<predefine>",
strings.HasPrefix(fn, "predefined_"):
// ignore
default:
a = append(a, string(dict.S(k)))
}
}
}
sort.Strings(a)
for _, v := range a {
m := ast.Macros[dict.SID(v)]
if m.Value == nil {
log.Fatal("TODO")
}
switch t := m.Type; t.Kind() {
case
cc.Int, cc.UInt, cc.Long, cc.ULong, cc.LongLong, cc.ULongLong,
cc.Float, cc.LongDouble, cc.Bool:
fmt.Fprintf(buf, "X%s = %v\n", v, m.Value)
case cc.Ptr:
switch t := t.Element(); t.Kind() {
case cc.Char:
fmt.Fprintf(buf, "X%s = %q\n", v, dict.S(int(m.Value.(cc.StringLitID))))
default:
log.Fatalf("%v", t.Kind())
}
default:
log.Fatalf("%v", t.Kind())
}
}
a = a[:0]
for _, v := range ast.Declarations.Identifiers {
switch x := v.Node.(type) {
case *cc.DirectDeclarator:
d := x.TopDeclarator()
id, _ := d.Identifier()
if x.EnumVal == nil {
break
}
a = append(a, string(dict.S(id)))
default:
log.Fatalf("%T", x)
}
}
sort.Strings(a)
for _, v := range a {
dd := ast.Declarations.Identifiers[dict.SID(v)].Node.(*cc.DirectDeclarator)
fmt.Fprintf(buf, "X%s = %v\n", v, dd.EnumVal)
}
}
func main() {
const repo = "sqlite.org/sqlite-amalgamation-3180000/"
log.SetFlags(log.Lshortfile | log.Lmicroseconds)
flag.Parse()
pth := findRepo(repo)
if pth == "" {
log.Fatalf("repository not found: %v", repo)
return
}
asta, bin := build(
`
//#define SQLITE_DEBUG 1
//#define SQLITE_ENABLE_API_ARMOR 1
#define SQLITE_ENABLE_MEMSYS5 1
#define SQLITE_USE_URI 1
`,
[][]string{
{"main.c"},
{filepath.Join(pth, "sqlite3.c")},
},
cc.EnableAnonymousStructFields(),
cc.IncludePaths([]string{pth}),
)
var b0 bytes.Buffer
enc := gob.NewEncoder(&b0)
if err := enc.Encode(&bin); err != nil {
log.Fatal(err)
}
var b1 bytes.Buffer
comp := gzip.NewWriter(&b1)
if _, err := comp.Write(b0.Bytes()); err != nil {
log.Fatal(err)
}
if err := comp.Close(); err != nil {
log.Fatal(err)
}
var b2 buffer.Bytes
lic, err := ioutil.ReadFile("SQLITE-LICENSE")
if err != nil {
log.Fatal(err)
}
b2.WriteString(`// Code generated by running "go generate". DO NOT EDIT.
/*
`)
b2.Write(lic)
b2.WriteString(`
*/
package bin
const (
`)
macros(&b2, asta[0])
b2.WriteString(`
Data = "`)
b := b1.Bytes()
for _, v := range b {
switch {
case v == '\\':
b2.WriteString(`\\`)
case v == '"':
b2.WriteString(`\"`)
case v < ' ', v >= 0x7f:
fmt.Fprintf(&b2, `\x%02x`, v)
default:
b2.WriteByte(v)
}
}
b2.WriteString(`"
)
`)
b3, err := format.Source(b2.Bytes())
if err != nil {
b3 = b
}
os.MkdirAll("internal/bin", 0775)
if err := ioutil.WriteFile(fmt.Sprintf("internal/bin/bin_%s_%s.go", runtime.GOOS, runtime.GOARCH), b3, 0664); err != nil {
log.Fatal(err)
}
log.Printf("code %#08x, text %#08x, data %#08x, bss %#08x, pc2func %v, pc2line %v, symbols %v, gz %v\n",
len(bin.Code), len(bin.Text), len(bin.Data), bin.BSS, len(bin.Functions), len(bin.Lines), len(bin.Sym), b1.Len(),
)
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff