2017-08-07 12:07:29 +02:00
|
|
|
// +build debug
|
|
|
|
|
|
|
|
package goparsify
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"runtime"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
2017-08-09 13:18:14 +02:00
|
|
|
var parsers []*debugParser
|
2017-08-07 12:07:29 +02:00
|
|
|
|
2017-08-09 13:18:14 +02:00
|
|
|
type debugParser struct {
|
2017-08-07 12:07:29 +02:00
|
|
|
Description string
|
|
|
|
Caller string
|
|
|
|
Next Parser
|
|
|
|
Time time.Duration
|
|
|
|
Calls int
|
|
|
|
}
|
|
|
|
|
2017-08-09 13:18:14 +02:00
|
|
|
func (dp *debugParser) Parse(ps *State) Result {
|
2017-08-07 12:07:29 +02:00
|
|
|
start := time.Now()
|
|
|
|
|
|
|
|
ret := dp.Next(ps)
|
|
|
|
|
|
|
|
dp.Time = dp.Time + time.Since(start)
|
|
|
|
dp.Calls++
|
|
|
|
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func getPackageName(f *runtime.Func) string {
|
|
|
|
parts := strings.Split(f.Name(), ".")
|
|
|
|
pl := len(parts)
|
|
|
|
|
|
|
|
if parts[pl-2][0] == '(' {
|
|
|
|
return strings.Join(parts[0:pl-2], ".")
|
|
|
|
} else {
|
|
|
|
return strings.Join(parts[0:pl-1], ".")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-09 13:18:14 +02:00
|
|
|
// NewParser should be called around the creation of every Parser.
|
|
|
|
// It does nothing normally and should incur no runtime overhead, but when building with -tags debug
|
|
|
|
// it will instrument every parser to collect valuable timing information displayable with DumpDebugStats.
|
2017-08-07 12:07:29 +02:00
|
|
|
func NewParser(description string, p Parser) Parser {
|
|
|
|
fpcs := make([]uintptr, 1)
|
|
|
|
caller := ""
|
|
|
|
|
|
|
|
for i := 1; i < 10; i++ {
|
|
|
|
n := runtime.Callers(i, fpcs)
|
|
|
|
|
|
|
|
if n != 0 {
|
|
|
|
frame := runtime.FuncForPC(fpcs[0] - 1)
|
|
|
|
pkg := getPackageName(frame)
|
|
|
|
|
|
|
|
if pkg != "github.com/vektah/goparsify" {
|
|
|
|
file, line := frame.FileLine(fpcs[0] - 1)
|
|
|
|
caller = fmt.Sprintf("%s:%d", file, line)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-09 13:18:14 +02:00
|
|
|
dp := &debugParser{
|
2017-08-07 12:07:29 +02:00
|
|
|
Description: description,
|
|
|
|
Next: p,
|
|
|
|
Caller: caller,
|
|
|
|
}
|
|
|
|
|
|
|
|
parsers = append(parsers, dp)
|
|
|
|
return dp.Parse
|
|
|
|
}
|
|
|
|
|
2017-08-09 13:18:14 +02:00
|
|
|
// DumpDebugStats will print out the curring timings for each parser if built with -tags debug
|
2017-08-07 12:07:29 +02:00
|
|
|
func DumpDebugStats() {
|
|
|
|
sort.Slice(parsers, func(i, j int) bool {
|
|
|
|
return parsers[i].Time >= parsers[j].Time
|
|
|
|
})
|
|
|
|
|
|
|
|
fmt.Println("Parser stats:")
|
|
|
|
for _, parser := range parsers {
|
|
|
|
fmt.Printf("%20s\t%10s\t%10d\tcalls\t%s\n", parser.Description, parser.Time.String(), parser.Calls, parser.Caller)
|
|
|
|
}
|
|
|
|
}
|