mini micro optimizations

This commit is contained in:
Arpad Ryszka 2017-07-30 02:35:51 +02:00
parent ff26b83b95
commit 1b21b8fde2
7 changed files with 142 additions and 91 deletions

12
.gitignore vendored
View File

@ -1,14 +1,2 @@
# Binaries for programs and plugins
*.exe
*.dll
*.so
*.dylib
# Test binary, build with `go test -c`
*.test *.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out *.out
# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/

View File

@ -14,4 +14,15 @@ check: build
fmt: $(SOURCES) fmt: $(SOURCES)
@gofmt -w -s $(SOURCES) @gofmt -w -s $(SOURCES)
cpu.out: $(SOURCES)
go test -v -run TestMMLFile -cpuprofile cpu.out
cpu: cpu.out
go tool pprof -top cpu.out
precommit: fmt build check precommit: fmt build check
clean:
@rm -f *.test
@rm -f cpu.out
@go clean -i ./...

19
char.go
View File

@ -68,6 +68,22 @@ func (p *charParser) match(t rune) bool {
return p.not return p.not
} }
func (p *charParser) matchBuild(t rune) bool {
for _, ci := range p.chars {
if ci == t {
return !p.not
}
}
for _, ri := range p.ranges {
if t >= ri[0] && t <= ri[1] {
return !p.not
}
}
return p.not
}
func (p *charParser) parse(t Trace, c *context) { func (p *charParser) parse(t Trace, c *context) {
// t = t.Extend(p.name) // t = t.Extend(p.name)
// t.Out1("parsing", c.offset) // t.Out1("parsing", c.offset)
@ -86,12 +102,13 @@ func (p *charParser) parse(t Trace, c *context) {
} }
func (p *charParser) build(c *context) ([]*Node, bool) { func (p *charParser) build(c *context) ([]*Node, bool) {
// TODO: how to remove this check
t, ok := c.token() t, ok := c.token()
if !ok { if !ok {
panic("damaged parser context") panic("damaged parser context")
} }
if !p.match(t) { if !p.matchBuild(t) {
return nil, false return nil, false
} }

View File

@ -22,7 +22,7 @@ type choiceBuilder struct {
id int id int
commit CommitType commit CommitType
elements []builder elements []builder
includedBy []int includedBy *idSet
} }
func newChoice(name string, ct CommitType, elements []string) *choiceDefinition { func newChoice(name string, ct CommitType, elements []string) *choiceDefinition {
@ -41,9 +41,10 @@ func (d *choiceDefinition) commitType() CommitType { return d.commit }
func (d *choiceDefinition) init(r *registry) error { func (d *choiceDefinition) init(r *registry) error {
if d.cbuilder == nil { if d.cbuilder == nil {
d.cbuilder = &choiceBuilder{ d.cbuilder = &choiceBuilder{
name: d.name, name: d.name,
id: d.id, id: d.id,
commit: d.commit, commit: d.commit,
includedBy: &idSet{},
} }
} }
@ -70,13 +71,14 @@ func (d *choiceDefinition) setIncludedBy(r *registry, includedBy int, parsers *i
if d.cbuilder == nil { if d.cbuilder == nil {
d.cbuilder = &choiceBuilder{ d.cbuilder = &choiceBuilder{
name: d.name, name: d.name,
id: d.id, id: d.id,
commit: d.commit, commit: d.commit,
includedBy: &idSet{},
} }
} }
d.cbuilder.includedBy = appendIfMissing(d.cbuilder.includedBy, includedBy) d.cbuilder.includedBy.set(includedBy)
parsers.set(d.id) parsers.set(d.id)
return setItemsIncludedBy(r, d.elements, includedBy, parsers) return setItemsIncludedBy(r, d.elements, includedBy, parsers)
@ -131,9 +133,10 @@ func (d *choiceDefinition) parser(r *registry, parsers *idSet) (parser, error) {
func (d *choiceDefinition) builder() builder { func (d *choiceDefinition) builder() builder {
if d.cbuilder == nil { if d.cbuilder == nil {
d.cbuilder = &choiceBuilder{ d.cbuilder = &choiceBuilder{
name: d.name, name: d.name,
id: d.id, id: d.id,
commit: d.commit, commit: d.commit,
includedBy: &idSet{},
} }
} }
@ -172,9 +175,10 @@ func (p *choiceParser) parse(t Trace, c *context) {
var match bool var match bool
var nextTo int var nextTo int
var elementIndex int var elementIndex int
var foundMatch bool
for { for {
var foundMatch bool foundMatch = false
elementIndex = 0 elementIndex = 0
for elementIndex < len(p.elements) { for elementIndex < len(p.elements) {
@ -222,19 +226,14 @@ func (b *choiceBuilder) nodeName() string { return b.name }
func (b *choiceBuilder) nodeID() int { return b.id } func (b *choiceBuilder) nodeID() int { return b.id }
func (b *choiceBuilder) build(c *context) ([]*Node, bool) { func (b *choiceBuilder) build(c *context) ([]*Node, bool) {
to, ok := c.store.takeMatch(c.offset, b.id) to, ok := c.store.takeMatch(c.offset, b.id, b.includedBy)
if !ok { if !ok {
return nil, false return nil, false
} }
for _, ib := range b.includedBy {
c.store.takeMatchLength(c.offset, ib, to)
}
var element builder var element builder
for _, e := range b.elements { for _, e := range b.elements {
elementTo, match, _ := c.store.getMatch(c.offset, e.nodeID()) if c.store.hasMatchTo(c.offset, e.nodeID(), to) {
if match && elementTo == to {
element = e element = e
break break
} }

View File

@ -90,13 +90,21 @@ func (c *context) exclude(offset int, id int) {
} }
} }
for i := range c.isExcluded[id] {
if c.isExcluded[id][i] == -1 {
c.isExcluded[id][i] = offset
return
}
}
c.isExcluded[id] = append(c.isExcluded[id], offset) c.isExcluded[id] = append(c.isExcluded[id], offset)
} }
func (c *context) include(offset int, id int) { func (c *context) include(offset int, id int) {
for i := range c.isExcluded[id] { for i := range c.isExcluded[id] {
if c.isExcluded[id][i] == offset { if c.isExcluded[id][i] == offset {
c.isExcluded[id] = append(c.isExcluded[id][:i], c.isExcluded[id][i+1:]...) // c.isExcluded[id] = append(c.isExcluded[id][:i], c.isExcluded[id][i+1:]...)
c.isExcluded[id][i] = -1
break break
} }
} }

View File

@ -25,7 +25,8 @@ type sequenceBuilder struct {
commit CommitType commit CommitType
items []builder items []builder
ranges [][]int ranges [][]int
includedBy []int includedBy *idSet
allChars bool
} }
func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefinition { func newSequence(name string, ct CommitType, items []SequenceItem) *sequenceDefinition {
@ -48,12 +49,14 @@ func (d *sequenceDefinition) includeItems() bool {
func (d *sequenceDefinition) init(r *registry) error { func (d *sequenceDefinition) init(r *registry) error {
if d.sbuilder == nil { if d.sbuilder == nil {
d.sbuilder = &sequenceBuilder{ d.sbuilder = &sequenceBuilder{
name: d.name, name: d.name,
id: d.id, id: d.id,
commit: d.commit, commit: d.commit,
includedBy: &idSet{},
} }
} }
allChars := true
for _, item := range d.items { for _, item := range d.items {
if item.Min == 0 && item.Max == 0 { if item.Min == 0 && item.Max == 0 {
item.Min, item.Max = 1, 1 item.Min, item.Max = 1, 1
@ -69,9 +72,16 @@ func (d *sequenceDefinition) init(r *registry) error {
} }
d.sbuilder.items = append(d.sbuilder.items, def.builder()) d.sbuilder.items = append(d.sbuilder.items, def.builder())
if allChars {
if _, isChar := def.(*charParser); !isChar {
allChars = false
}
}
} }
d.sbuilder.ranges = d.ranges d.sbuilder.ranges = d.ranges
d.sbuilder.allChars = allChars
if !d.includeItems() { if !d.includeItems() {
return nil return nil
@ -91,13 +101,14 @@ func (d *sequenceDefinition) setIncludedBy(r *registry, includedBy int, parsers
if d.sbuilder == nil { if d.sbuilder == nil {
d.sbuilder = &sequenceBuilder{ d.sbuilder = &sequenceBuilder{
name: d.name, name: d.name,
id: d.id, id: d.id,
commit: d.commit, commit: d.commit,
includedBy: &idSet{},
} }
} }
d.sbuilder.includedBy = appendIfMissing(d.sbuilder.includedBy, includedBy) d.sbuilder.includedBy.set(includedBy)
if !d.includeItems() { if !d.includeItems() {
return nil return nil
@ -158,9 +169,10 @@ func (d *sequenceDefinition) parser(r *registry, parsers *idSet) (parser, error)
func (d *sequenceDefinition) builder() builder { func (d *sequenceDefinition) builder() builder {
if d.sbuilder == nil { if d.sbuilder == nil {
d.sbuilder = &sequenceBuilder{ d.sbuilder = &sequenceBuilder{
name: d.name, name: d.name,
id: d.id, id: d.id,
commit: d.commit, commit: d.commit,
includedBy: &idSet{},
} }
} }
@ -186,16 +198,13 @@ func (p *sequenceParser) parse(t Trace, c *context) {
return return
} }
// if c.store.hasNoMatch(c.offset, p.id) {
// c.fail(c.offset)
// }
c.exclude(c.offset, p.id) c.exclude(c.offset, p.id)
itemIndex := 0 itemIndex := 0
var currentCount int var currentCount int
from := c.offset from := c.offset
to := c.offset to := c.offset
var parsed bool
for itemIndex < len(p.items) { for itemIndex < len(p.items) {
// TODO: is it ok to parse before max range check? what if max=0 // TODO: is it ok to parse before max range check? what if max=0
@ -214,7 +223,7 @@ func (p *sequenceParser) parse(t Trace, c *context) {
continue continue
} }
parsed := c.offset > to parsed = c.offset > to
if parsed { if parsed {
currentCount++ currentCount++
} }
@ -244,13 +253,24 @@ func (b *sequenceBuilder) nodeName() string { return b.name }
func (b *sequenceBuilder) nodeID() int { return b.id } func (b *sequenceBuilder) nodeID() int { return b.id }
func (b *sequenceBuilder) build(c *context) ([]*Node, bool) { func (b *sequenceBuilder) build(c *context) ([]*Node, bool) {
to, ok := c.store.takeMatch(c.offset, b.id) to, ok := c.store.takeMatch(c.offset, b.id, b.includedBy)
if !ok { if !ok {
return nil, false return nil, false
} }
for _, ib := range b.includedBy { if b.allChars {
c.store.takeMatchLength(c.offset, ib, to) from := c.offset
c.offset = to
if b.commit&Alias != 0 {
return nil, true
}
return []*Node{{
Name: b.name,
From: from,
To: to,
tokens: c.tokens,
}}, true
} }
from := c.offset from := c.offset

View File

@ -10,16 +10,8 @@ type store struct {
match [][]int match [][]int
} }
func (s *store) hasNoMatch(offset, id int) bool {
if len(s.noMatch) <= offset || s.noMatch[offset] == nil {
return false
}
return s.noMatch[offset].has(id)
}
func (s *store) getMatch(offset, id int) (int, bool, bool) { func (s *store) getMatch(offset, id int) (int, bool, bool) {
if s.hasNoMatch(offset, id) { if len(s.noMatch) > offset && s.noMatch[offset] != nil && s.noMatch[offset].has(id) {
return 0, false, true return 0, false, true
} }
@ -46,11 +38,29 @@ func (s *store) getMatch(offset, id int) (int, bool, bool) {
return to, found, found return to, found, found
} }
func (s *store) takeMatch(offset, id int) (int, bool) { func (s *store) hasMatchTo(offset, id, to int) bool {
if s.hasNoMatch(offset, id) { if len(s.noMatch) > offset && s.noMatch[offset] != nil && s.noMatch[offset].has(id) {
return 0, false return false
} }
if len(s.match) <= offset {
return false
}
for i := 0; i < len(s.match[offset]); i += 2 {
if s.match[offset][i] != id {
continue
}
if s.match[offset][i+1] == to {
return true
}
}
return false
}
func (s *store) takeMatch(offset, id int, includedBy *idSet) (int, bool) {
if len(s.match) <= offset { if len(s.match) <= offset {
return 0, false return 0, false
} }
@ -75,43 +85,27 @@ func (s *store) takeMatch(offset, id int) (int, bool) {
if found { if found {
s.match[offset][index] = -1 s.match[offset][index] = -1
for i := 0; i < len(s.match[offset]); i += 2 {
if includedBy.has(s.match[offset][i]) && s.match[offset][i+1] == to {
s.match[offset][i] = -1
}
}
} }
return to, found return to, found
} }
func (s *store) takeMatchLength(offset, id, to int) (int, bool) { func (s *store) takeMatchLength(offset, id, to int) {
if s.hasNoMatch(offset, id) {
return 0, false
}
if len(s.match) <= offset { if len(s.match) <= offset {
return 0, false return
} }
var (
found bool
// index int
)
for i := 0; i < len(s.match[offset]); i += 2 { for i := 0; i < len(s.match[offset]); i += 2 {
if s.match[offset][i] != id { if s.match[offset][i] == id && s.match[offset][i+1] == to {
continue
}
found = true
if s.match[offset][i+1] == to {
s.match[offset][i] = -1 s.match[offset][i] = -1
return to, true return
//eindex = i
} }
} }
if found {
// s.match[offset][index] = -1
}
return to, found
} }
func (s *store) ensureOffset(offset int) { func (s *store) ensureOffset(offset int) {
@ -131,15 +125,29 @@ func (s *store) ensureOffset(offset int) {
} }
func (s *store) setMatch(offset, id, to int) { func (s *store) setMatch(offset, id, to int) {
if toe, match, ok := s.getMatch(offset, id); ok && match && toe == to { s.ensureOffset(offset)
for i := 0; i < len(s.match[offset]); i += 2 {
if s.match[offset][i] != id || s.match[offset][i+1] != to {
continue
}
return return
} }
s.ensureOffset(offset)
s.match[offset] = append(s.match[offset], id, to) s.match[offset] = append(s.match[offset], id, to)
} }
func (s *store) setNoMatch(offset, id int) { func (s *store) setNoMatch(offset, id int) {
if len(s.match) > offset {
for i := 0; i < len(s.match[offset]); i += 2 {
if s.match[offset][i] != id {
continue
}
return
}
}
if len(s.noMatch) <= offset { if len(s.noMatch) <= offset {
if cap(s.noMatch) > offset { if cap(s.noMatch) > offset {
s.noMatch = s.noMatch[:offset+1] s.noMatch = s.noMatch[:offset+1]