model/profile.go
Rama main · réplica de lectura del repositorio original.
package model
import (
"path"
"regexp"
"sort"
"strings"
)
type ProfileCategory string
const (
ProfileCategoryNone = ""
ProfileCategoryCPU = "cpu"
ProfileCategoryMemory = "memory"
ProfileCategoryLock = "lock"
ProfileCategoryIO = "io"
)
type ProfileType string
const (
ProfileTypeNodeAgentCPU ProfileType = "ebpf:cpu:nanoseconds"
ProfileTypeNodeAgentIOTime ProfileType = "ebpf:io_time:nanoseconds"
ProfileTypeNodeAgentIORead ProfileType = "ebpf:io_read:bytes"
ProfileTypeNodeAgentIOWrite ProfileType = "ebpf:io_write:bytes"
ProfileTypeGoCPU ProfileType = "go:profile_cpu:nanoseconds"
ProfileTypeGoHeapAllocObjects ProfileType = "go:heap_alloc_objects:count"
ProfileTypeGoHeapAllocSpace ProfileType = "go:heap_alloc_space:bytes"
ProfileTypeGoHeapInuseObjects ProfileType = "go:heap_inuse_objects:count"
ProfileTypeGoHeapInuseSpace ProfileType = "go:heap_inuse_space:bytes"
ProfileTypeGoGoroutines ProfileType = "go:goroutine_goroutine:count"
ProfileTypeGoBlockContentions ProfileType = "go:block_contentions:count"
ProfileTypeGoBlockDelay ProfileType = "go:block_delay:nanoseconds"
ProfileTypeGoMutexContentions ProfileType = "go:mutex_contentions:count"
ProfileTypeGoMutexDelay ProfileType = "go:mutex_delay:nanoseconds"
ProfileTypeGoRuntimeHeapAllocObjects ProfileType = "go_runtime:heap_alloc_objects:count"
ProfileTypeGoRuntimeHeapAllocSpace ProfileType = "go_runtime:heap_alloc_space:bytes"
ProfileTypeGoRuntimeHeapInuseObjects ProfileType = "go_runtime:heap_inuse_objects:count"
ProfileTypeGoRuntimeHeapInuseSpace ProfileType = "go_runtime:heap_inuse_space:bytes"
ProfileTypeJavaHeapAllocObjects ProfileType = "java:heap_alloc_objects:count"
ProfileTypeJavaHeapAllocSpace ProfileType = "java:heap_alloc_space:bytes"
ProfileTypeJavaCPU ProfileType = "java:cpu:nanoseconds"
ProfileTypeJavaLockContentions ProfileType = "java:lock_contentions:count"
ProfileTypeJavaLockDelay ProfileType = "java:lock_delay:nanoseconds"
)
type ProfileAggregation string
const (
ProfileAggregationSum ProfileAggregation = "sum"
ProfileAggregationAvg ProfileAggregation = "avg"
)
type ProfileMeta struct {
Category ProfileCategory
Name string
Aggregation ProfileAggregation
Featured bool
NodeAgent bool
}
type Profile struct {
Type ProfileType `json:"type"`
FlameGraph *FlameGraphNode `json:"flamegraph"`
Diff bool `json:"diff"`
}
var (
Profiles = map[ProfileType]ProfileMeta{
ProfileTypeNodeAgentCPU: {
Category: ProfileCategoryCPU,
Name: "CPU (eBPF)",
Aggregation: ProfileAggregationSum,
NodeAgent: true,
},
ProfileTypeNodeAgentIOTime: {
Category: ProfileCategoryIO,
Name: "Disk I/O time (eBPF)",
Aggregation: ProfileAggregationSum,
NodeAgent: true,
},
ProfileTypeNodeAgentIORead: {
Category: ProfileCategoryIO,
Name: "Disk read bytes (eBPF)",
Aggregation: ProfileAggregationSum,
NodeAgent: true,
},
ProfileTypeNodeAgentIOWrite: {
Category: ProfileCategoryIO,
Name: "Disk write bytes (eBPF)",
Aggregation: ProfileAggregationSum,
NodeAgent: true,
},
ProfileTypeGoCPU: {
Category: ProfileCategoryCPU,
Name: "CPU",
Aggregation: ProfileAggregationSum,
Featured: true,
},
ProfileTypeGoHeapAllocObjects: {
Category: ProfileCategoryMemory,
Name: "Memory (alloc_objects)",
Aggregation: ProfileAggregationSum,
},
ProfileTypeGoHeapAllocSpace: {
Category: ProfileCategoryMemory,
Name: "Memory (alloc_space)",
Aggregation: ProfileAggregationSum,
},
ProfileTypeGoHeapInuseObjects: {
Category: ProfileCategoryMemory,
Name: "Memory (inuse_objects)",
Aggregation: ProfileAggregationAvg,
},
ProfileTypeGoHeapInuseSpace: {
Category: ProfileCategoryMemory,
Name: "Memory (inuse_space)",
Aggregation: ProfileAggregationAvg,
Featured: true,
},
ProfileTypeGoGoroutines: {
Name: "Golang (goroutines)",
Aggregation: ProfileAggregationAvg,
},
ProfileTypeGoBlockContentions: {
Name: "Golang (block_contentions)",
Aggregation: ProfileAggregationSum,
},
ProfileTypeGoBlockDelay: {
Name: "Golang (block_delay)",
Aggregation: ProfileAggregationSum,
},
ProfileTypeGoMutexContentions: {
Name: "Golang (mutex_contentions)",
Aggregation: ProfileAggregationSum,
},
ProfileTypeGoMutexDelay: {
Name: "Golang (mutex_delay)",
Aggregation: ProfileAggregationSum,
},
ProfileTypeGoRuntimeHeapAllocObjects: {
Category: ProfileCategoryMemory,
Name: "Go Memory (alloc_objects)",
Aggregation: ProfileAggregationSum,
NodeAgent: true,
},
ProfileTypeGoRuntimeHeapAllocSpace: {
Category: ProfileCategoryMemory,
Name: "Go Memory (alloc_space)",
Aggregation: ProfileAggregationSum,
NodeAgent: true,
Featured: true,
},
ProfileTypeGoRuntimeHeapInuseObjects: {
Category: ProfileCategoryMemory,
Name: "Go Memory (inuse_objects)",
Aggregation: ProfileAggregationAvg,
NodeAgent: true,
},
ProfileTypeGoRuntimeHeapInuseSpace: {
Category: ProfileCategoryMemory,
Name: "Go Memory (inuse_space)",
Aggregation: ProfileAggregationAvg,
NodeAgent: true,
Featured: true,
},
ProfileTypeJavaHeapAllocObjects: {
Category: ProfileCategoryMemory,
Name: "Java Memory (alloc_objects)",
Aggregation: ProfileAggregationSum,
NodeAgent: true,
},
ProfileTypeJavaHeapAllocSpace: {
Category: ProfileCategoryMemory,
Name: "Java Memory (alloc_space)",
Aggregation: ProfileAggregationSum,
NodeAgent: true,
Featured: true,
},
ProfileTypeJavaCPU: {
Category: ProfileCategoryCPU,
Name: "Java CPU (async-profiler)",
Aggregation: ProfileAggregationSum,
NodeAgent: true,
},
ProfileTypeJavaLockContentions: {
Category: ProfileCategoryLock,
Name: "Java Lock (contentions)",
Aggregation: ProfileAggregationSum,
NodeAgent: true,
},
ProfileTypeJavaLockDelay: {
Category: ProfileCategoryLock,
Name: "Java Lock (delay)",
Aggregation: ProfileAggregationSum,
NodeAgent: true,
Featured: true,
},
}
)
type FlameGraphNode struct {
Name string `json:"name"`
Total int64 `json:"total"`
Self int64 `json:"self"`
Comp int64 `json:"comp"`
Children []*FlameGraphNode `json:"children"`
ColorBy string `json:"color_by"`
Data map[string]string `json:"data"`
}
func (n *FlameGraphNode) InsertStack(stack []string, value int64, comp *int64) {
node := n
l := len(stack) - 1
for i := range stack {
node.Total += value
if comp != nil {
node.Comp += *comp
}
s := stack[l-i]
node = node.Insert(s)
}
node.Total += value
node.Self += value
if comp != nil {
node.Comp += *comp
}
}
func (n *FlameGraphNode) Insert(s string) *FlameGraphNode {
name, colorBy := parseStackFunction(s)
i := sort.Search(len(n.Children), func(i int) bool {
return strings.Compare(n.Children[i].Name, name) >= 0
})
if i > len(n.Children)-1 || n.Children[i].Name != name {
child := &FlameGraphNode{Name: name, ColorBy: colorBy}
n.Children = append(n.Children, child)
copy(n.Children[i+1:], n.Children[i:])
n.Children[i] = child
}
return n.Children[i]
}
func (n *FlameGraphNode) Diff(comparison *FlameGraphNode) {
n.diff(comparison)
n.Comp = comparison.Total
n.Total += n.Comp
}
func (n *FlameGraphNode) diff(comparison *FlameGraphNode) {
byName := map[string]*FlameGraphNode{}
if comparison != nil {
for _, ch := range comparison.Children {
byName[ch.Name] = ch
}
}
seen := map[*FlameGraphNode]bool{}
for _, ch := range n.Children {
comp := byName[ch.Name]
if byName[ch.Name] != nil {
ch.Comp = comp.Total
ch.Total += ch.Comp
for k, v := range comp.Data {
if ch.Data == nil {
ch.Data = map[string]string{}
}
ch.Data[k] = v
}
seen[comp] = true
}
ch.diff(comp)
}
if comparison != nil {
for _, ch := range comparison.Children {
if !seen[ch] {
ch.Comp = ch.Total
n.Children = append(n.Children, ch)
}
}
}
}
var (
javaFuncRe = regexp.MustCompile(`^(([0-9a-z.]+)\.[^.]+\.[^(]+)\(`)
)
func parseStackFunction(sf string) (string, string) {
parts := strings.Split(sf, " ")
var colorBy string
if len(parts) == 2 {
if i := strings.LastIndexByte(parts[0], '/'); i > 0 {
colorBy = parts[0][:i]
}
return parts[0], colorBy
}
// python
if len(parts) == 3 {
if strings.HasSuffix(parts[0], ".py") {
file := parts[0]
if i := strings.Index(file, "site-packages/"); i != -1 {
file = file[i+len("site-packages/"):]
colorBy = path.Dir(file)
} else {
colorBy = file
}
return parts[1] + " @" + file, colorBy
}
}
// java
if len(parts) >= 3 {
matches := javaFuncRe.FindStringSubmatch(parts[1])
if len(matches) == 3 {
return matches[1], matches[2]
}
}
if i := strings.LastIndexByte(sf, ' '); i > 0 {
return sf[:i], ""
}
return sf, ""
}