-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathping_rtt.go
95 lines (81 loc) · 2.3 KB
/
ping_rtt.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package exporter
import (
"math"
"sort"
"time"
)
// PingMetrics is a dumb data point computed from a list of PingResults.
type PingMetrics struct {
PacketsSent int // number of packets sent
PacketsLost int // number of packets lost
Best time.Duration // best RTT
Worst time.Duration // worst RTT
Median time.Duration // median RTT
Mean time.Duration // mean RTT
StdDev time.Duration // RTT std deviation
}
// PingResult stores the information about a single ping, in particular
// the round-trip time or whether the packet was lost.
type PingResult struct {
RTT time.Duration
Lost bool
}
// PingHistory represents the ping history for a single node/device.
type PingHistory []PingResult
// NewHistory creates a new History object with a specific capacity.
func NewHistory(capacity int) PingHistory {
return make(PingHistory, 0, capacity)
}
// AddResult saves a ping result into the internal history.
func (h *PingHistory) Add(rtt time.Duration, lost bool) {
*h = append(*h, PingResult{RTT: rtt, Lost: lost})
}
// Compute aggregates the result history into a single data point.
func (h PingHistory) Compute() *PingMetrics {
numFailure := 0
numTotal := len(h)
if numTotal == 0 {
return nil
}
data := make([]float64, 0, numTotal)
var best, worst, mean, stddev, total, sumSquares float64
for _, curr := range h {
if curr.Lost {
numFailure++
continue
}
rtt := curr.RTT.Seconds()
if rtt < best || len(data) == 0 {
best = rtt
}
if rtt > worst || len(data) == 0 {
worst = rtt
}
data = append(data, rtt)
total += rtt
}
size := float64(numTotal - numFailure)
mean = total / size
for _, rtt := range data {
sumSquares += math.Pow(rtt-mean, 2)
}
stddev = math.Sqrt(sumSquares / size)
median := math.NaN()
if l := len(data); l > 0 {
sort.Float64Slice(data).Sort()
if l%2 == 0 {
median = (data[l/2-1] + data[l/2]) / 2
} else {
median = data[l/2]
}
}
return &PingMetrics{
PacketsSent: numTotal,
PacketsLost: numFailure,
Best: time.Duration(best * float64(time.Second)),
Worst: time.Duration(worst * float64(time.Second)),
Median: time.Duration(median * float64(time.Second)),
Mean: time.Duration(mean * float64(time.Second)),
StdDev: time.Duration(stddev * float64(time.Second)),
}
}