OSDN Git Service

run time performance measure (#553)
[bytom/vapor.git] / toolbar / measure / method.go
diff --git a/toolbar/measure/method.go b/toolbar/measure/method.go
new file mode 100644 (file)
index 0000000..dbb3b63
--- /dev/null
@@ -0,0 +1,83 @@
+package measure
+
+import (
+       "fmt"
+       "runtime/debug"
+       "strings"
+       "sync"
+
+       log "github.com/sirupsen/logrus"
+)
+
+const (
+       logModule = "measure"
+)
+
+var store sync.Map
+
+// Start trigger record of stack trace run time record as a graph view
+func Start() {
+       routineID, stacks, err := traceStacks()
+       if err != nil {
+               log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on measure get stacks")
+               return
+       }
+
+       data, ok := store.Load(routineID)
+       if !ok {
+               store.Store(routineID, NewTimer(stacks[0]))
+               return
+       }
+
+       if err := data.(*Timer).StartTimer(stacks); err != nil {
+               log.WithFields(log.Fields{"module": logModule, "err": err, "routine": routineID, "stack": stacks}).Error("fail on start timer")
+       }
+}
+
+// End end the stack trace run time
+func End() {
+       routineID, stacks, err := traceStacks()
+       if err != nil {
+               log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on measure get stacks")
+               return
+       }
+
+       data, ok := store.Load(routineID)
+       if !ok {
+               log.WithFields(log.Fields{"module": logModule, "err": err}).Error("fail on measure timer by routine ID")
+               return
+       }
+
+       rootTimer := data.(*Timer)
+       if err := rootTimer.EndTimer(stacks); err != nil {
+               log.WithFields(log.Fields{"module": logModule, "err": err, "routine": routineID, "stack": stacks}).Error("fail on end timer")
+       }
+
+       if rootTimer.IsEnd() {
+               log.WithField("module", logModule).Info(rootTimer.String())
+               store.Delete(routineID)
+       }
+}
+
+func traceStacks() (string, []string, error) {
+       stacks := []string{}
+       for _, stack := range strings.Split(string(debug.Stack()), "\n") {
+               // skip the file path stack
+               if strings.HasPrefix(stack, "   ") {
+                       continue
+               }
+
+               // delete the func memory address stuff
+               if subPos := strings.LastIndexAny(stack, "("); subPos > 0 {
+                       stacks = append(stacks, stack[:subPos])
+               } else {
+                       stacks = append(stacks, stack)
+               }
+       }
+
+       if len(stacks) < 4 {
+               return "", nil, fmt.Errorf("fail to decode stack")
+       }
+
+       return stacks[0], stacks[4:], nil
+}