mirror of https://github.com/divan/expvarmon.git
Add GC intervals
This commit is contained in:
parent
036e299988
commit
b93e309f19
16
data.go
16
data.go
|
@ -10,8 +10,8 @@ type UIData struct {
|
|||
|
||||
SparklineData []*SparklineData
|
||||
|
||||
HasGCPauses bool
|
||||
HasGCTimes bool
|
||||
HasGCPauses bool
|
||||
HasGCIntervals bool
|
||||
}
|
||||
|
||||
// SparklineData holds additional data needed for sparklines.
|
||||
|
@ -49,13 +49,21 @@ func NewUIData(vars []VarName, services []*Service) *UIData {
|
|||
}
|
||||
return false
|
||||
}
|
||||
hasGCIntervals := func(vars []VarName) bool {
|
||||
for _, v := range vars {
|
||||
if v.Kind() == KindGCIntervals {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return &UIData{
|
||||
Services: services,
|
||||
Vars: vars,
|
||||
SparklineData: sp,
|
||||
|
||||
HasGCPauses: hasGCPauses(vars),
|
||||
HasGCTimes: true,
|
||||
HasGCPauses: hasGCPauses(vars),
|
||||
HasGCIntervals: hasGCIntervals(vars),
|
||||
}
|
||||
}
|
||||
|
|
98
ui_single.go
98
ui_single.go
|
@ -76,23 +76,27 @@ func (t *TermUISingle) Init(data UIData) error {
|
|||
return s
|
||||
}()
|
||||
|
||||
t.BarChart = func() *termui.BarChart {
|
||||
bc := termui.NewBarChart()
|
||||
bc.Border.Label = "Bar Chart"
|
||||
bc.TextColor = termui.ColorGreen
|
||||
bc.BarColor = termui.ColorGreen
|
||||
bc.NumColor = termui.ColorBlack
|
||||
return bc
|
||||
}()
|
||||
if data.HasGCPauses {
|
||||
t.BarChart = func() *termui.BarChart {
|
||||
bc := termui.NewBarChart()
|
||||
bc.Border.Label = "Bar Chart"
|
||||
bc.TextColor = termui.ColorGreen
|
||||
bc.BarColor = termui.ColorGreen
|
||||
bc.NumColor = termui.ColorBlack
|
||||
return bc
|
||||
}()
|
||||
}
|
||||
|
||||
t.BarChart2 = func() *termui.BarChart {
|
||||
bc := termui.NewBarChart()
|
||||
bc.Border.Label = "Bar Chart"
|
||||
bc.TextColor = termui.ColorGreen
|
||||
bc.BarColor = termui.ColorGreen
|
||||
bc.NumColor = termui.ColorBlack
|
||||
return bc
|
||||
}()
|
||||
if data.HasGCIntervals {
|
||||
t.BarChart2 = func() *termui.BarChart {
|
||||
bc := termui.NewBarChart()
|
||||
bc.Border.Label = "Bar Chart"
|
||||
bc.TextColor = termui.ColorGreen
|
||||
bc.BarColor = termui.ColorGreen
|
||||
bc.NumColor = termui.ColorBlack
|
||||
return bc
|
||||
}()
|
||||
}
|
||||
|
||||
t.Relayout()
|
||||
|
||||
|
@ -153,9 +157,28 @@ func (t *TermUISingle) Update(data UIData) {
|
|||
t.BarChart.DataLabels = labels
|
||||
t.BarChart.Border.Label = "GC Pauses (last 256)"
|
||||
|
||||
}
|
||||
|
||||
if data.HasGCIntervals {
|
||||
var gcintervals *GCIntervals
|
||||
for _, v := range service.Vars {
|
||||
if v.Kind() == KindGCIntervals {
|
||||
gcintervals = v.(*GCIntervals)
|
||||
break
|
||||
}
|
||||
}
|
||||
hist := gcintervals.Histogram(t.bins)
|
||||
values, counts := hist.BarchartData()
|
||||
vals := make([]int, 0, len(counts))
|
||||
labels := make([]string, 0, len(counts))
|
||||
for i := 0; i < len(counts); i++ {
|
||||
vals = append(vals, int(counts[i]))
|
||||
d := roundDuration(time.Duration(values[i]))
|
||||
labels = append(labels, d.String())
|
||||
}
|
||||
t.BarChart2.Data = vals
|
||||
t.BarChart2.DataLabels = labels
|
||||
t.BarChart2.Border.Label = "GC Pauses (last 256)"
|
||||
t.BarChart2.Border.Label = "Intervals between GC (last 256)"
|
||||
}
|
||||
|
||||
t.Relayout()
|
||||
|
@ -165,7 +188,7 @@ func (t *TermUISingle) Update(data UIData) {
|
|||
if data.HasGCPauses {
|
||||
widgets = append(widgets, t.BarChart)
|
||||
}
|
||||
if data.HasGCTimes {
|
||||
if data.HasGCIntervals {
|
||||
widgets = append(widgets, t.BarChart2)
|
||||
}
|
||||
for _, par := range t.Pars {
|
||||
|
@ -221,20 +244,35 @@ func (t *TermUISingle) Relayout() {
|
|||
t.Sparkline.Height = calcHeight
|
||||
t.Sparkline.Y = th - h
|
||||
|
||||
// Fourth row: Barchart
|
||||
bins, binWidth := recalcBins(tw / 2)
|
||||
t.bins = bins
|
||||
// Fourth row: Barcharts
|
||||
var barchartWidth, charts int
|
||||
if t.BarChart != nil {
|
||||
charts++
|
||||
}
|
||||
if t.BarChart2 != nil {
|
||||
charts++
|
||||
}
|
||||
|
||||
t.BarChart.Width = tw / 2
|
||||
t.BarChart.Height = h - calcHeight
|
||||
t.BarChart.Y = th - t.BarChart.Height
|
||||
t.BarChart.BarWidth = binWidth
|
||||
if charts > 0 {
|
||||
barchartWidth = tw / charts
|
||||
bins, binWidth := recalcBins(barchartWidth)
|
||||
t.bins = bins
|
||||
|
||||
t.BarChart2.Width = tw / 2
|
||||
t.BarChart2.X = tw / 2
|
||||
t.BarChart2.Height = h - calcHeight
|
||||
t.BarChart2.Y = th - t.BarChart.Height
|
||||
t.BarChart2.BarWidth = binWidth
|
||||
if t.BarChart != nil {
|
||||
t.BarChart.Width = barchartWidth
|
||||
t.BarChart.Height = h - calcHeight
|
||||
t.BarChart.Y = th - t.BarChart.Height
|
||||
t.BarChart.BarWidth = binWidth
|
||||
}
|
||||
|
||||
if t.BarChart2 != nil {
|
||||
t.BarChart2.Width = barchartWidth
|
||||
t.BarChart2.X = 0 + barchartWidth
|
||||
t.BarChart2.Height = h - calcHeight
|
||||
t.BarChart2.Y = th - t.BarChart.Height
|
||||
t.BarChart2.BarWidth = binWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// recalcBins attempts to select optimal value for the number
|
||||
|
|
71
var.go
71
var.go
|
@ -26,6 +26,7 @@ const (
|
|||
KindDuration
|
||||
KindString
|
||||
KindGCPauses
|
||||
KindGCIntervals
|
||||
)
|
||||
|
||||
// Var represents arbitrary value for variable.
|
||||
|
@ -57,6 +58,8 @@ func NewVar(name VarName) Var {
|
|||
return &String{}
|
||||
case KindGCPauses:
|
||||
return &GCPauses{}
|
||||
case KindGCIntervals:
|
||||
return &GCIntervals{}
|
||||
default:
|
||||
return &Number{}
|
||||
}
|
||||
|
@ -204,7 +207,70 @@ func (v *GCPauses) Histogram(bins int) *Histogram {
|
|||
return hist
|
||||
}
|
||||
|
||||
// TODO: add boolean, timestamp, gcpauses, gcendtimes types
|
||||
// GCIntervals represents GC pauses intervals.
|
||||
//
|
||||
// It uses memstat.PauseEnd circular buffer w/
|
||||
// timestamps.
|
||||
type GCIntervals struct {
|
||||
intervals [256]uint64
|
||||
}
|
||||
|
||||
func (v *GCIntervals) Kind() VarKind { return KindGCIntervals }
|
||||
func (v *GCIntervals) String() string { return "" }
|
||||
func (v *GCIntervals) Set(j *jason.Value) {
|
||||
v.intervals = [256]uint64{}
|
||||
if j == nil {
|
||||
return
|
||||
}
|
||||
// as original array contains UNIX timestamps,
|
||||
// we want to calculate diffs to previous values (interval)
|
||||
// and work with them
|
||||
duration := func(a, b int64) uint64 {
|
||||
dur := int64(a - b)
|
||||
if dur < 0 {
|
||||
dur = -dur
|
||||
}
|
||||
return uint64(dur)
|
||||
}
|
||||
var prev int64
|
||||
if arr, err := j.Array(); err == nil {
|
||||
for i := 1; i < len(arr); i++ {
|
||||
p, _ := arr[i].Int64()
|
||||
|
||||
v.intervals[i] = duration(p, prev)
|
||||
prev = p
|
||||
}
|
||||
|
||||
// process last and fist elems
|
||||
p, _ := arr[0].Int64()
|
||||
v.intervals[0] = duration(p, prev)
|
||||
}
|
||||
}
|
||||
func (v *GCIntervals) Histogram(bins int) *Histogram {
|
||||
hist := NewHistogram(bins)
|
||||
|
||||
// we need to skip maximum value here
|
||||
// because it's always a diff between last and fist
|
||||
// elem in cicrular buffer (we don't know NumGC)
|
||||
var max uint64
|
||||
for i := 0; i < 256; i++ {
|
||||
if v.intervals[i] > max {
|
||||
max = v.intervals[i]
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 256; i++ {
|
||||
// we ignore zeros, since
|
||||
// its never the case, but
|
||||
// we have zeros on the very beginning
|
||||
if v.intervals[i] > 0 && v.intervals[i] != max {
|
||||
hist.Add(v.intervals[i])
|
||||
}
|
||||
}
|
||||
return hist
|
||||
}
|
||||
|
||||
// TODO: add boolean, timestamp, types
|
||||
|
||||
// ToSlice converts "dot-separated" notation into the "slice of strings".
|
||||
//
|
||||
|
@ -245,6 +311,9 @@ func (v VarName) Kind() VarKind {
|
|||
if v.Long() == "memstats.PauseNs" {
|
||||
return KindGCPauses
|
||||
}
|
||||
if v.Long() == "memstats.PauseEnd" {
|
||||
return KindGCIntervals
|
||||
}
|
||||
|
||||
start := strings.IndexRune(string(v), ':')
|
||||
if start == -1 {
|
||||
|
|
22
var_test.go
22
var_test.go
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue