From 17ad74b4fc21d2ac31872e4aadec6da1d1d1b005 Mon Sep 17 00:00:00 2001 From: Vikram Rangnekar Date: Sun, 16 Jun 2019 15:28:50 -0400 Subject: [PATCH] Futher reduce allocations across hot paths --- psql/bench.1 | 7 ----- psql/bench.2 | 7 ----- psql/bench.3 | 7 ----- psql/bench.6 | 7 +++++ psql/bench.7 | 7 +++++ psql/bench.8 | 7 +++++ qcode/parse.go | 7 ++--- qcode/qcode.go | 80 +++++++++++++++++++++++++++----------------------- qcode/stack.go | 47 +++++++++++++++++++++++++++++ 9 files changed, 115 insertions(+), 61 deletions(-) delete mode 100644 psql/bench.1 delete mode 100644 psql/bench.2 delete mode 100644 psql/bench.3 create mode 100644 psql/bench.6 create mode 100644 psql/bench.7 create mode 100644 psql/bench.8 create mode 100644 qcode/stack.go diff --git a/psql/bench.1 b/psql/bench.1 deleted file mode 100644 index 26d6905..0000000 --- a/psql/bench.1 +++ /dev/null @@ -1,7 +0,0 @@ -goos: darwin -goarch: amd64 -pkg: github.com/dosco/super-graph/psql -BenchmarkCompile-8 50000 27388 ns/op 4983 B/op 136 allocs/op -BenchmarkCompileParallel-8 200000 8864 ns/op 5046 B/op 136 allocs/op -PASS -ok github.com/dosco/super-graph/psql 3.528s diff --git a/psql/bench.2 b/psql/bench.2 deleted file mode 100644 index 7a374d2..0000000 --- a/psql/bench.2 +++ /dev/null @@ -1,7 +0,0 @@ -goos: darwin -goarch: amd64 -pkg: github.com/dosco/super-graph/psql -BenchmarkCompile-8 50000 26899 ns/op 4984 B/op 136 allocs/op -BenchmarkCompileParallel-8 200000 8128 ns/op 5046 B/op 136 allocs/op -PASS -ok github.com/dosco/super-graph/psql 3.455s diff --git a/psql/bench.3 b/psql/bench.3 deleted file mode 100644 index d400c4f..0000000 --- a/psql/bench.3 +++ /dev/null @@ -1,7 +0,0 @@ -goos: darwin -goarch: amd64 -pkg: github.com/dosco/super-graph/psql -BenchmarkCompile-8 50000 25670 ns/op 4533 B/op 134 allocs/op -BenchmarkCompileParallel-8 200000 7533 ns/op 4590 B/op 134 allocs/op -PASS -ok github.com/dosco/super-graph/psql 3.149s diff --git a/psql/bench.6 b/psql/bench.6 new file mode 100644 index 0000000..9724f6f --- /dev/null +++ b/psql/bench.6 @@ -0,0 +1,7 @@ +goos: darwin +goarch: amd64 +pkg: github.com/dosco/super-graph/psql +BenchmarkCompile-8 1000000 15997 ns/op 3048 B/op 58 allocs/op +BenchmarkCompileParallel-8 3000000 4722 ns/op 3073 B/op 58 allocs/op +PASS +ok github.com/dosco/super-graph/psql 35.024s diff --git a/psql/bench.7 b/psql/bench.7 new file mode 100644 index 0000000..1deee4b --- /dev/null +++ b/psql/bench.7 @@ -0,0 +1,7 @@ +goos: darwin +goarch: amd64 +pkg: github.com/dosco/super-graph/psql +BenchmarkCompile-8 100000 16829 ns/op 2887 B/op 57 allocs/op +BenchmarkCompileParallel-8 300000 5450 ns/op 2911 B/op 57 allocs/op +PASS +ok github.com/dosco/super-graph/psql 3.561s diff --git a/psql/bench.8 b/psql/bench.8 new file mode 100644 index 0000000..014931c --- /dev/null +++ b/psql/bench.8 @@ -0,0 +1,7 @@ +goos: darwin +goarch: amd64 +pkg: github.com/dosco/super-graph/psql +BenchmarkCompile-8 100000 15246 ns/op 2823 B/op 53 allocs/op +BenchmarkCompileParallel-8 300000 4559 ns/op 2848 B/op 53 allocs/op +PASS +ok github.com/dosco/super-graph/psql 3.116s diff --git a/qcode/parse.go b/qcode/parse.go index b1f42d5..7bd10fa 100644 --- a/qcode/parse.go +++ b/qcode/parse.go @@ -70,6 +70,7 @@ type Node struct { Val string Parent *Node Children []*Node + exp *Exp } var zeroNode = Node{} @@ -217,10 +218,8 @@ func (p *Parser) peek(types ...itemType) bool { } func (p *Parser) parseOp() (*Operation, error) { - if p.peek(itemQuery, itemMutation, itemSub) == false { - err := fmt.Errorf( - "expecting a query, mutation or subscription (not '%s')", - p.val(p.next())) + if !p.peek(itemQuery, itemMutation, itemSub) { + err := errors.New("expecting a query, mutation or subscription") return nil, err } item := p.next() diff --git a/qcode/qcode.go b/qcode/qcode.go index 0d583be..731c0aa 100644 --- a/qcode/qcode.go +++ b/qcode/qcode.go @@ -179,6 +179,11 @@ func NewCompiler(c Config) (*Compiler, error) { fm[plural] = fil } + seedExp := [100]Exp{} + for i := range seedExp { + expPool.Put(&seedExp[i]) + } + return &Compiler{fl, fm, bl, c.KeepArgs}, nil } @@ -233,7 +238,7 @@ func (com *Compiler) compileQuery(op *Operation) (*Query, error) { parentID := int32(0) selects := make([]Select, 0, 5) - st := util.NewStack() + st := NewStack() if len(op.Fields) == 0 { return nil, errors.New("empty query") @@ -249,12 +254,7 @@ func (com *Compiler) compileQuery(op *Operation) (*Query, error) { return nil, fmt.Errorf("selector limit reached (%d)", maxSelectors) } - intf := st.Pop() - fid, ok := intf.(int32) - - if !ok { - return nil, fmt.Errorf("15: unexpected value %v (%t)", intf, intf) - } + fid := st.Pop() field := &op.Fields[fid] if _, ok := com.bl[field.Name]; ok { @@ -328,7 +328,10 @@ func (com *Compiler) compileQuery(op *Operation) (*Query, error) { if root.Where != nil { ow := root.Where - root.Where = &Exp{Op: OpAnd} + + root.Where = expPool.Get().(*Exp) + root.Where.Reset() + root.Where.Op = OpAnd root.Where.Children = root.Where.childrenA[:2] root.Where.Children[0] = fil root.Where.Children[1] = ow @@ -387,11 +390,6 @@ func (com *Compiler) compileArgs(sel *Select, args []Arg) error { return nil } -type expT struct { - parent *Exp - node *Node -} - func (com *Compiler) compileArgObj(arg *Arg) (*Exp, error) { if arg.Val.Type != nodeObj { return nil, fmt.Errorf("expecting an object") @@ -408,7 +406,7 @@ func (com *Compiler) compileArgNode(node *Node, usePool bool) (*Exp, error) { return nil, errors.New("invalid argument value") } - st.Push(&expT{nil, node.Children[0]}) + pushChild(st, nil, node) for { if st.Len() == 0 { @@ -416,18 +414,22 @@ func (com *Compiler) compileArgNode(node *Node, usePool bool) (*Exp, error) { } intf := st.Pop() - eT, ok := intf.(*expT) - if !ok || eT == nil { + node, ok := intf.(*Node) + if !ok || node == nil { return nil, fmt.Errorf("16: unexpected value %v (%t)", intf, intf) } - if len(eT.node.Name) != 0 { - if _, ok := com.bl[eT.node.Name]; ok { + if len(node.Name) == 0 { + pushChildren(st, node.exp, node) + continue + + } else { + if _, ok := com.bl[node.Name]; ok { continue } } - ex, err := newExp(st, eT, usePool) + ex, err := newExp(st, node, usePool) if err != nil { return nil, err } @@ -436,18 +438,19 @@ func (com *Compiler) compileArgNode(node *Node, usePool bool) (*Exp, error) { continue } - if eT.parent == nil { + if node.exp == nil { root = ex } else { - eT.parent.Children = append(eT.parent.Children, ex) + node.exp.Children = append(node.exp.Children, ex) } + } if com.ka { return root, nil } - st.Push(node.Children[0]) + pushChild(st, nil, node) for { if st.Len() == 0 { @@ -503,7 +506,10 @@ func (com *Compiler) compileArgSearch(sel *Select, arg *Arg) error { if sel.Where != nil { ow := sel.Where - sel.Where = &Exp{Op: OpAnd} + + sel.Where = expPool.Get().(*Exp) + sel.Where.Reset() + sel.Where.Op = OpAnd sel.Where.Children = sel.Where.childrenA[:2] sel.Where.Children[0] = ex sel.Where.Children[1] = ow @@ -523,7 +529,10 @@ func (com *Compiler) compileArgWhere(sel *Select, arg *Arg) error { if sel.Where != nil { ow := sel.Where - sel.Where = &Exp{Op: OpAnd} + + sel.Where = expPool.Get().(*Exp) + sel.Where.Reset() + sel.Where.Op = OpAnd sel.Where.Children = sel.Where.childrenA[:2] sel.Where.Children[0] = ex sel.Where.Children[1] = ow @@ -659,14 +668,7 @@ func compileSub() (*Query, error) { return nil, nil } -func newExp(st *util.Stack, eT *expT, usePool bool) (*Exp, error) { - node := eT.node - - if len(node.Name) == 0 { - pushChildren(st, eT.parent, node) - return nil, nil - } - +func newExp(st *util.Stack, node *Node, usePool bool) (*Exp, error) { name := node.Name if name[0] == '_' { name = name[1:] @@ -691,7 +693,7 @@ func newExp(st *util.Stack, eT *expT, usePool bool) (*Exp, error) { pushChildren(st, ex, node) case "not": ex.Op = OpNot - st.Push(&expT{ex, node.Children[0]}) + pushChild(st, ex, node) case "eq", "equals": ex.Op = OpEquals ex.Val = node.Val @@ -753,7 +755,7 @@ func newExp(st *util.Stack, eT *expT, usePool bool) (*Exp, error) { ex.Op = OpIsNull ex.Val = node.Val default: - pushChildren(st, eT.parent, node) + pushChildren(st, node.exp, node) return nil, nil // skip node } @@ -836,12 +838,18 @@ func setOrderByColName(ob *OrderBy, node *Node) { } } -func pushChildren(st *util.Stack, ex *Exp, node *Node) { +func pushChildren(st *util.Stack, exp *Exp, node *Node) { for i := range node.Children { - st.Push(&expT{ex, node.Children[i]}) + node.Children[i].exp = exp + st.Push(node.Children[i]) } } +func pushChild(st *util.Stack, exp *Exp, node *Node) { + node.Children[0].exp = exp + st.Push(node.Children[0]) +} + func compileFilter(filter []string) (*Exp, error) { var fl *Exp com := &Compiler{} diff --git a/qcode/stack.go b/qcode/stack.go new file mode 100644 index 0000000..9790cff --- /dev/null +++ b/qcode/stack.go @@ -0,0 +1,47 @@ +package qcode + +type Stack struct { + stA [20]int32 + st []int32 + top int +} + +// Create a new Stack +func NewStack() *Stack { + s := &Stack{top: -1} + s.st = s.stA[:0] + return s +} + +// Return the number of items in the Stack +func (s *Stack) Len() int { + return (s.top + 1) +} + +// View the top item on the Stack +func (s *Stack) Peek() int32 { + if s.top == -1 { + return -1 + } + return s.st[s.top] +} + +// Pop the top item of the Stack and return it +func (s *Stack) Pop() int32 { + if s.top == -1 { + return -1 + } + + s.top-- + return s.st[(s.top + 1)] +} + +// Push a value onto the top of the Stack +func (s *Stack) Push(value int32) { + s.top++ + if len(s.st) <= s.top { + s.st = append(s.st, value) + } else { + s.st[s.top] = value + } +}