77291e4b44
Add unlisted LogLongTick developer setting. Rearrange the order of the shutdown signal handler to figure out where it might fail.
118 lines
2.5 KiB
Go
118 lines
2.5 KiB
Go
package counters
|
|
|
|
import (
|
|
"database/sql"
|
|
"math"
|
|
"time"
|
|
|
|
c "github.com/Azareal/Gosora/common"
|
|
qgen "github.com/Azareal/Gosora/query_gen"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
var PerfCounter *DefaultPerfCounter
|
|
|
|
type PerfCounterBucket struct {
|
|
low *MutexCounter64Bucket
|
|
high *MutexCounter64Bucket
|
|
avg *MutexCounter64Bucket
|
|
}
|
|
|
|
// TODO: Track perf on a per route basis
|
|
type DefaultPerfCounter struct {
|
|
buckets []*PerfCounterBucket
|
|
|
|
insert *sql.Stmt
|
|
}
|
|
|
|
func NewDefaultPerfCounter(acc *qgen.Accumulator) (*DefaultPerfCounter, error) {
|
|
co := &DefaultPerfCounter{
|
|
buckets: []*PerfCounterBucket{
|
|
{
|
|
low: &MutexCounter64Bucket{counter: math.MaxInt64},
|
|
high: &MutexCounter64Bucket{counter: 0},
|
|
avg: &MutexCounter64Bucket{counter: 0},
|
|
},
|
|
},
|
|
insert: acc.Insert("perfchunks").Columns("low,high,avg,createdAt").Fields("?,?,?,UTC_TIMESTAMP()").Prepare(),
|
|
}
|
|
|
|
c.Tasks.FifteenMin.Add(co.Tick)
|
|
//c.Tasks.Sec.Add(co.Tick)
|
|
c.Tasks.Shutdown.Add(co.Tick)
|
|
return co, acc.FirstError()
|
|
}
|
|
|
|
func (co *DefaultPerfCounter) Tick() error {
|
|
getCounter := func(b *MutexCounter64Bucket) (c int64) {
|
|
b.Lock()
|
|
c = b.counter
|
|
b.counter = 0
|
|
b.Unlock()
|
|
return c
|
|
}
|
|
var low int64
|
|
hTbl := c.GetHookTable()
|
|
for _, b := range co.buckets {
|
|
b.low.Lock()
|
|
low, b.low.counter = b.low.counter, math.MaxInt64
|
|
b.low.Unlock()
|
|
if low == math.MaxInt64 {
|
|
low = 0
|
|
}
|
|
high := getCounter(b.high)
|
|
avg := getCounter(b.avg)
|
|
c.H_counters_perf_tick_row_hook(hTbl, low, high, avg)
|
|
|
|
e := co.insertChunk(low, high, avg) // TODO: Bulk insert for speed?
|
|
if e != nil {
|
|
return errors.Wrap(errors.WithStack(e), "perf counter")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (co *DefaultPerfCounter) insertChunk(low, high, avg int64) error {
|
|
if low == 0 && high == 0 && avg == 0 {
|
|
return nil
|
|
}
|
|
c.DebugLogf("Inserting a pchunk with low %d, high %d, avg %d", low, high, avg)
|
|
_, e := co.insert.Exec(low, high, avg)
|
|
return e
|
|
}
|
|
|
|
func (co *DefaultPerfCounter) Push(dur time.Duration /*,_ bool*/) {
|
|
id := 0
|
|
b := co.buckets[id]
|
|
//c.DebugDetail("buckets[", id, "]: ", b)
|
|
micro := dur.Microseconds()
|
|
if micro >= math.MaxInt32 {
|
|
c.LogWarning(errors.New("dur should not be int32 max or higher"))
|
|
}
|
|
|
|
low := b.low
|
|
low.Lock()
|
|
if micro < low.counter {
|
|
low.counter = micro
|
|
}
|
|
low.Unlock()
|
|
|
|
high := b.high
|
|
high.Lock()
|
|
if micro > high.counter {
|
|
high.counter = micro
|
|
}
|
|
high.Unlock()
|
|
|
|
avg := b.avg
|
|
avg.Lock()
|
|
if micro != avg.counter {
|
|
if avg.counter == 0 {
|
|
avg.counter = micro
|
|
} else {
|
|
avg.counter = (micro + avg.counter) / 2
|
|
}
|
|
}
|
|
avg.Unlock()
|
|
}
|