init
This commit is contained in:
+105
@@ -0,0 +1,105 @@
|
||||
// Copyright 2015 Marc-Antoine Ruel. All rights reserved.
|
||||
// Use of this source code is governed under the Apache License, Version 2.0
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package stack
|
||||
|
||||
import (
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Similarity is the level at which two call lines arguments must match to be
|
||||
// considered similar enough to coalesce them.
|
||||
type Similarity int
|
||||
|
||||
const (
|
||||
// ExactFlags requires same bits (e.g. Locked).
|
||||
ExactFlags Similarity = iota
|
||||
// ExactLines requests the exact same arguments on the call line.
|
||||
ExactLines
|
||||
// AnyPointer considers different pointers a similar call line.
|
||||
AnyPointer
|
||||
// AnyValue accepts any value as similar call line.
|
||||
AnyValue
|
||||
)
|
||||
|
||||
// Aggregate merges similar goroutines into buckets.
|
||||
//
|
||||
// The buckets are ordered in library provided order of relevancy. You can
|
||||
// reorder at your chosing.
|
||||
func Aggregate(goroutines []*Goroutine, similar Similarity) []*Bucket {
|
||||
type count struct {
|
||||
ids []int
|
||||
first bool
|
||||
}
|
||||
b := map[*Signature]*count{}
|
||||
// O(n²). Fix eventually.
|
||||
for _, routine := range goroutines {
|
||||
found := false
|
||||
for key, c := range b {
|
||||
// When a match is found, this effectively drops the other goroutine ID.
|
||||
if key.similar(&routine.Signature, similar) {
|
||||
found = true
|
||||
c.ids = append(c.ids, routine.ID)
|
||||
c.first = c.first || routine.First
|
||||
if !key.equal(&routine.Signature) {
|
||||
// Almost but not quite equal. There's different pointers passed
|
||||
// around but the same values. Zap out the different values.
|
||||
newKey := key.merge(&routine.Signature)
|
||||
b[newKey] = c
|
||||
delete(b, key)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
// Create a copy of the Signature, since it will be mutated.
|
||||
key := &Signature{}
|
||||
*key = routine.Signature
|
||||
b[key] = &count{ids: []int{routine.ID}, first: routine.First}
|
||||
}
|
||||
}
|
||||
out := make(buckets, 0, len(b))
|
||||
for signature, c := range b {
|
||||
sort.Ints(c.ids)
|
||||
out = append(out, &Bucket{Signature: *signature, IDs: c.ids, First: c.first})
|
||||
}
|
||||
sort.Sort(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// Bucket is a stack trace signature and the list of goroutines that fits this
|
||||
// signature.
|
||||
type Bucket struct {
|
||||
Signature
|
||||
// IDs is the ID of each Goroutine with this Signature.
|
||||
IDs []int
|
||||
// First is true if this Bucket contains the first goroutine, e.g. the one
|
||||
// Signature that likely generated the panic() call, if any.
|
||||
First bool
|
||||
}
|
||||
|
||||
// less does reverse sort.
|
||||
func (b *Bucket) less(r *Bucket) bool {
|
||||
if b.First || r.First {
|
||||
return b.First
|
||||
}
|
||||
return b.Signature.less(&r.Signature)
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
// buckets is a list of Bucket sorted by repeation count.
|
||||
type buckets []*Bucket
|
||||
|
||||
func (b buckets) Len() int {
|
||||
return len(b)
|
||||
}
|
||||
|
||||
func (b buckets) Less(i, j int) bool {
|
||||
return b[i].less(b[j])
|
||||
}
|
||||
|
||||
func (b buckets) Swap(i, j int) {
|
||||
b[j], b[i] = b[i], b[j]
|
||||
}
|
||||
Reference in New Issue
Block a user