/
opmon.go
118 lines (102 loc) · 2.47 KB
/
opmon.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package opmon
import (
"sync"
"time"
"sort"
"fmt"
"os"
"github.com/xiaonanln/goworld/engine/consts"
"github.com/xiaonanln/goworld/engine/gwlog"
)
var (
operationAllocPool = sync.Pool{
New: func() interface{} {
return &Operation{}
},
}
monitor = newMonitor()
)
func init() {
if consts.OPMON_DUMP_INTERVAL > 0 {
go func() {
for {
time.Sleep(consts.OPMON_DUMP_INTERVAL)
monitor.Dump()
}
}()
}
}
type _OpInfo struct {
count uint64
totalDuration time.Duration
maxDuration time.Duration
}
type _Monitor struct {
sync.Mutex
opInfos map[string]*_OpInfo
}
func newMonitor() *_Monitor {
m := &_Monitor{
opInfos: map[string]*_OpInfo{},
}
return m
}
func (monitor *_Monitor) record(opname string, duration time.Duration) {
monitor.Lock()
info := monitor.opInfos[opname]
if info == nil {
info = &_OpInfo{}
monitor.opInfos[opname] = info
}
info.count += 1
info.totalDuration += duration
if duration > info.maxDuration {
info.maxDuration = duration
}
monitor.Unlock()
}
func (monitor *_Monitor) Dump() {
type _T struct {
name string
info *_OpInfo
}
var opInfos map[string]*_OpInfo
monitor.Lock()
opInfos = monitor.opInfos
monitor.opInfos = map[string]*_OpInfo{} // clear to be empty
monitor.Unlock()
var copyOpInfos []_T
for name, opinfo := range opInfos {
copyOpInfos = append(copyOpInfos, _T{name, opinfo})
}
sort.Slice(copyOpInfos, func(i, j int) bool {
_t1 := copyOpInfos[i]
_t2 := copyOpInfos[j]
return _t1.name < _t2.name
})
fmt.Fprint(os.Stderr, "=====================================================================================\n")
for _, _t := range copyOpInfos {
opname, opinfo := _t.name, _t.info
fmt.Fprintf(os.Stderr, "%-30sx%-10d AVG %-10s MAX %-10s\n", opname, opinfo.count, opinfo.totalDuration/time.Duration(opinfo.count), opinfo.maxDuration)
}
}
// Operation is the type of operation to be monitored
type Operation struct {
name string
startTime time.Time
}
// StartOperation creates a new operation
func StartOperation(operationName string) *Operation {
op := operationAllocPool.Get().(*Operation)
op.name = operationName
op.startTime = time.Now()
return op
}
// Finish finishes the operation and records the duration of operation
func (op *Operation) Finish(warnThreshold time.Duration) {
takeTime := time.Now().Sub(op.startTime)
monitor.record(op.name, takeTime)
if takeTime >= warnThreshold {
gwlog.Warnf("opmon: operation %s takes %s > %s", op.name, takeTime, warnThreshold)
}
}