93 lines
1.8 KiB
Go
93 lines
1.8 KiB
Go
package web
|
|
|
|
import (
|
|
"encoding/json"
|
|
"log"
|
|
|
|
. "openreplay/backend/pkg/messages"
|
|
"openreplay/backend/pkg/messages/performance"
|
|
)
|
|
|
|
/*
|
|
Handler name: CpuIssue
|
|
Input events: PerformanceTrack,
|
|
SetPageLocation
|
|
Output event: IssueEvent
|
|
*/
|
|
|
|
const CPU_THRESHOLD = 70 // % out of 100
|
|
const CPU_MIN_DURATION_TRIGGER = 6 * 1000
|
|
|
|
type CpuIssueDetector struct {
|
|
startTimestamp uint64
|
|
startMessageID uint64
|
|
lastTimestamp uint64
|
|
maxRate uint64
|
|
contextString string
|
|
}
|
|
|
|
func (f *CpuIssueDetector) Build() Message {
|
|
if f.startTimestamp == 0 {
|
|
return nil
|
|
}
|
|
duration := f.lastTimestamp - f.startTimestamp
|
|
timestamp := f.startTimestamp
|
|
messageID := f.startMessageID
|
|
maxRate := f.maxRate
|
|
|
|
f.startTimestamp = 0
|
|
f.startMessageID = 0
|
|
f.maxRate = 0
|
|
if duration < CPU_MIN_DURATION_TRIGGER {
|
|
return nil
|
|
}
|
|
|
|
payload, err := json.Marshal(struct {
|
|
Duration uint64
|
|
Rate uint64
|
|
}{duration, maxRate})
|
|
if err != nil {
|
|
log.Printf("can't marshal CpuIssue payload to json: %s", err)
|
|
}
|
|
|
|
return &IssueEvent{
|
|
Type: "cpu",
|
|
Timestamp: timestamp,
|
|
MessageID: messageID,
|
|
ContextString: f.contextString,
|
|
Payload: string(payload),
|
|
}
|
|
}
|
|
|
|
func (f *CpuIssueDetector) Handle(message Message, messageID uint64, timestamp uint64) Message {
|
|
switch msg := message.(type) {
|
|
case *PerformanceTrack:
|
|
dt := performance.TimeDiff(timestamp, f.lastTimestamp)
|
|
if dt == 0 {
|
|
return nil // TODO: handle error
|
|
}
|
|
|
|
f.lastTimestamp = timestamp
|
|
|
|
if msg.Frames == -1 || msg.Ticks == -1 {
|
|
return f.Build()
|
|
}
|
|
|
|
cpuRate := performance.CPURate(msg.Ticks, dt)
|
|
|
|
if cpuRate >= CPU_THRESHOLD {
|
|
if f.startTimestamp == 0 {
|
|
f.startTimestamp = timestamp
|
|
f.startMessageID = messageID
|
|
}
|
|
if f.maxRate < cpuRate {
|
|
f.maxRate = cpuRate
|
|
}
|
|
} else {
|
|
return f.Build()
|
|
}
|
|
case *SetPageLocation:
|
|
f.contextString = msg.URL
|
|
}
|
|
return nil
|
|
}
|