Skip to content

Commit

Permalink
optimize node slices (#33)
Browse files Browse the repository at this point in the history
Use a single struct type `NodeSlice` to wrap all
kinds of `ast.Node` slices; this allows us to have
an allocation pool slice that can be used to
avoid allocations in most cases.

While some operations like `NodeSlice.At` become slower,
other operations like `NodeSlice.SliceInto` are far
more efficient: we can re-use memory even in re-slicing cases.

Benchmark results:

    name                           old time/op    new time/op    delta
    Match/failFast-8                  178ns ± 1%     182ns ± 1%   +2.18%  (p=0.000 n=10+10)
    Match/failCall-8                  427ns ± 1%     414ns ± 1%   -3.00%  (p=0.000 n=10+9)
    Match/failCallFast-8              176ns ± 0%     166ns ± 2%   -6.07%  (p=0.000 n=8+10)
    Match/assign-8                    251ns ± 1%     245ns ± 0%   -2.29%  (p=0.000 n=10+7)
    Match/assignMulti-8               874ns ± 2%     586ns ± 1%  -32.96%  (p=0.000 n=10+10)
    Match/simpleLit-8                 109ns ± 1%     104ns ± 4%   -4.15%  (p=0.000 n=10+10)
    Match/simpleBinaryOp-8            234ns ± 1%     235ns ± 4%     ~     (p=0.986 n=10+10)
    Match/simpleSelectorExpr-8        326ns ± 1%     308ns ± 1%   -5.55%  (p=0.000 n=9+10)
    Match/simpleCall-8                310ns ± 1%     296ns ± 1%   -4.25%  (p=0.000 n=10+10)
    Match/selectorExpr-8              343ns ± 1%     339ns ± 1%   -1.10%  (p=0.004 n=10+9)
    Match/sliceExpr-8                 261ns ± 1%     243ns ± 0%   -6.89%  (p=0.000 n=10+9)
    Match/any-8                       181ns ± 1%     187ns ± 3%   +3.04%  (p=0.000 n=10+10)
    Match/anyCall-8                   693ns ± 1%     514ns ± 1%  -25.87%  (p=0.000 n=10+10)
    Match/ifStmt-8                    558ns ± 1%     399ns ± 1%  -28.51%  (p=0.000 n=10+10)
    Match/optStmt1-8                  399ns ± 1%     375ns ± 1%   -6.13%  (p=0.000 n=10+10)
    Match/optStmt2-8                  276ns ± 1%     247ns ± 1%  -10.64%  (p=0.000 n=10+9)
    Match/namedOptStmt1-8            2.00µs ± 1%    1.61µs ± 1%  -19.18%  (p=0.000 n=9+10)
    Match/namedOptStmt2-8            1.33µs ± 1%    1.06µs ± 1%  -20.07%  (p=0.000 n=10+10)
    Match/branchStmt-8                139ns ± 1%     137ns ± 1%   -1.33%  (p=0.000 n=10+10)
    Match/multiStmt-8                1.23µs ± 1%    0.98µs ± 1%  -20.06%  (p=0.000 n=9+10)
    Match/multiExpr-8                1.33µs ± 1%    1.03µs ± 1%  -22.31%  (p=0.000 n=9+10)
    Match/variadicCall-8              254ns ± 2%     252ns ± 0%   -0.79%  (p=0.003 n=10+7)
    Match/capture1-8                  170ns ± 0%     167ns ± 1%   -2.24%  (p=0.000 n=9+9)
    Match/capture2-8                  257ns ± 1%     250ns ± 1%   -2.75%  (p=0.000 n=10+10)
    Match/capture8-8                  928ns ± 1%     919ns ± 1%   -0.95%  (p=0.000 n=10+10)
    Match/capture2same-8              296ns ± 1%     283ns ± 0%   -4.43%  (p=0.000 n=10+9)
    Match/capture8same-8             1.06µs ± 1%    1.03µs ± 1%   -3.41%  (p=0.000 n=9+10)
    Match/captureBacktrackLeft-8     1.65µs ± 1%    1.10µs ± 1%  -32.96%  (p=0.000 n=10+8)
    Match/captureBacktrackRight-8    1.08µs ± 2%    0.81µs ± 1%  -24.89%  (p=0.000 n=10+10)
    Match/exprList-8                 2.62µs ± 1%    2.32µs ± 1%  -11.61%  (p=0.000 n=10+8)
    [Geo mean]                        453ns          405ns       -10.66%

    name                           old alloc/op   new alloc/op   delta
    Match/failFast-8                  32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/failCall-8                  32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/failCallFast-8              32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/assign-8                    32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/assignMulti-8                192B ± 0%       96B ± 0%  -50.00%  (p=0.000 n=10+10)
    Match/simpleLit-8                 32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/simpleBinaryOp-8            32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/simpleSelectorExpr-8        32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/simpleCall-8                32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/selectorExpr-8              32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/sliceExpr-8                 32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/any-8                       32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/anyCall-8                    144B ± 0%       96B ± 0%  -33.33%  (p=0.000 n=10+10)
    Match/ifStmt-8                    80.0B ± 0%     32.0B ± 0%  -60.00%  (p=0.000 n=10+10)
    Match/optStmt1-8                  32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/optStmt2-8                  32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/namedOptStmt1-8              344B ± 0%      224B ± 0%  -34.88%  (p=0.000 n=10+10)
    Match/namedOptStmt2-8              168B ± 0%       96B ± 0%  -42.86%  (p=0.000 n=10+10)
    Match/branchStmt-8                32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/multiStmt-8                  256B ± 0%      160B ± 0%  -37.50%  (p=0.000 n=10+10)
    Match/multiExpr-8                  256B ± 0%      160B ± 0%  -37.50%  (p=0.000 n=10+10)
    Match/variadicCall-8              32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/capture1-8                  32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/capture2-8                  32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/capture8-8                  32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/capture2same-8              32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/capture8same-8              32.0B ± 0%     32.0B ± 0%     ~     (all equal)
    Match/captureBacktrackLeft-8       288B ± 0%       96B ± 0%  -66.67%  (p=0.000 n=10+10)
    Match/captureBacktrackRight-8      168B ± 0%       96B ± 0%  -42.86%  (p=0.000 n=10+10)
    Match/exprList-8                   256B ± 0%      160B ± 0%  -37.50%  (p=0.000 n=10+10)
    [Geo mean]                        59.0B          48.2B       -18.32%
  • Loading branch information
quasilyte authored Oct 2, 2022
1 parent dce9607 commit e78263d
Show file tree
Hide file tree
Showing 7 changed files with 357 additions and 145 deletions.
21 changes: 12 additions & 9 deletions compile.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,19 @@ func (c *compiler) compileNode(n ast.Node) {
c.compileStmt(n)
case *ast.ValueSpec:
c.compileValueSpec(n)
case stmtSlice:
c.compileStmtSlice(n)
case declSlice:
c.compileDeclSlice(n)
case ExprSlice:
c.compileExprSlice(n)
case *rangeClause:
c.compileRangeClause(n)
case *rangeHeader:
c.compileRangeHeader(n)
case *NodeSlice:
switch n.Kind {
case StmtNodeSlice:
c.compileStmtSlice(n.stmtSlice)
case DeclNodeSlice:
c.compileDeclSlice(n.declSlice)
case ExprNodeSlice:
c.compileExprSlice(n.exprSlice)
}
default:
panic(c.errorf(n, "compileNode: unexpected %T", n))
}
Expand Down Expand Up @@ -1191,15 +1194,15 @@ func (c *compiler) compileSendStmt(n *ast.SendStmt) {
c.compileExpr(n.Value)
}

func (c *compiler) compileDeclSlice(decls declSlice) {
func (c *compiler) compileDeclSlice(decls []ast.Decl) {
c.emitInstOp(opMultiDecl)
for _, n := range decls {
c.compileDecl(n)
}
c.emitInstOp(opEnd)
}

func (c *compiler) compileStmtSlice(stmts stmtSlice) {
func (c *compiler) compileStmtSlice(stmts []ast.Stmt) {
c.emitInstOp(opMultiStmt)
insideStmtList := c.insideStmtList
c.insideStmtList = true
Expand All @@ -1210,7 +1213,7 @@ func (c *compiler) compileStmtSlice(stmts stmtSlice) {
c.emitInstOp(opEnd)
}

func (c *compiler) compileExprSlice(exprs ExprSlice) {
func (c *compiler) compileExprSlice(exprs []ast.Expr) {
c.emitInstOp(opMultiExpr)
for _, n := range exprs {
c.compileExpr(n)
Expand Down
63 changes: 35 additions & 28 deletions gogrep.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func IsEmptyNodeSlice(n ast.Node) bool {
if list, ok := n.(NodeSlice); ok {
if list, ok := n.(*NodeSlice); ok {
return list.Len() == 0
}
return false
Expand Down Expand Up @@ -62,14 +62,18 @@ type MatcherState struct {
// actual matching phase)
capture []CapturedNode

nodeSlices []NodeSlice
nodeSlicesUsed int

pc int

partial PartialNode
}

func NewMatcherState() MatcherState {
return MatcherState{
capture: make([]CapturedNode, 0, 8),
capture: make([]CapturedNode, 0, 8),
nodeSlices: make([]NodeSlice, 16),
}
}

Expand Down Expand Up @@ -143,34 +147,37 @@ func Compile(config CompileConfig) (*Pattern, PatternInfo, error) {
}

func Walk(root ast.Node, fn func(n ast.Node) bool) {
switch root := root.(type) {
case ExprSlice:
for _, e := range root {
ast.Inspect(e, fn)
}
case stmtSlice:
for _, e := range root {
ast.Inspect(e, fn)
}
case fieldSlice:
for _, e := range root {
ast.Inspect(e, fn)
}
case identSlice:
for _, e := range root {
ast.Inspect(e, fn)
if root, ok := root.(*NodeSlice); ok {
switch root.Kind {
case ExprNodeSlice:
for _, e := range root.exprSlice {
ast.Inspect(e, fn)
}
case StmtNodeSlice:
for _, e := range root.stmtSlice {
ast.Inspect(e, fn)
}
case FieldNodeSlice:
for _, e := range root.fieldSlice {
ast.Inspect(e, fn)
}
case IdentNodeSlice:
for _, e := range root.identSlice {
ast.Inspect(e, fn)
}
case SpecNodeSlice:
for _, e := range root.specSlice {
ast.Inspect(e, fn)
}
default:
for _, e := range root.declSlice {
ast.Inspect(e, fn)
}
}
case specSlice:
for _, e := range root {
ast.Inspect(e, fn)
}
case declSlice:
for _, e := range root {
ast.Inspect(e, fn)
}
default:
ast.Inspect(root, fn)
return
}

ast.Inspect(root, fn)
}

func newPatternInfo() PatternInfo {
Expand Down
Loading

0 comments on commit e78263d

Please sign in to comment.