-
Notifications
You must be signed in to change notification settings - Fork 3.9k
/
Copy pathapp_stats.go
161 lines (140 loc) · 5.61 KB
/
app_stats.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright 2017 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
package roachpb
import (
"math"
"unsafe"
"github.com/cockroachdb/cockroach/pkg/util"
)
// StmtID is the type of a Statement ID.
type StmtID string
// ConstructStatementID constructs an ID by hashing an anonymized query, it's
// failure status, and if it was part of an implicit txn. At the time of writing,
// these are the axis' we use to bucket queries for stats collection
// (see stmtKey).
func ConstructStatementID(anonymizedStmt string, failed bool, implicitTxn bool) StmtID {
hash := util.FNV64Init()
for _, c := range anonymizedStmt {
hash = util.FNV64AddToHash(hash, c)
}
if failed {
hash = util.FNV64AddToHash(hash, 'F')
} else {
hash = util.FNV64AddToHash(hash, 'S')
}
if implicitTxn {
hash = util.FNV64AddToHash(hash, 'I')
} else {
hash = util.FNV64AddToHash(hash, 'E')
}
b := util.FNV64ToByteArray(hash)
return StmtID(*(*string)(unsafe.Pointer(&b)))
}
// GetVariance retrieves the variance of the values.
func (l *NumericStat) GetVariance(count int64) float64 {
return l.SquaredDiffs / (float64(count) - 1)
}
// Record updates the underlying running counts, incorporating the given value.
// It follows Welford's algorithm (Technometrics, 1962). The running count must
// be stored as it is required to finalize and retrieve the variance.
func (l *NumericStat) Record(count int64, val float64) {
delta := val - l.Mean
l.Mean += delta / float64(count)
l.SquaredDiffs += delta * (val - l.Mean)
}
// Add combines b into this derived statistics.
func (l *NumericStat) Add(b NumericStat, countA, countB int64) {
*l = AddNumericStats(*l, b, countA, countB)
}
// AlmostEqual compares two NumericStats between a window of size eps.
func (l *NumericStat) AlmostEqual(b NumericStat, eps float64) bool {
return math.Abs(l.Mean-b.Mean) <= eps &&
math.Abs(l.SquaredDiffs-b.SquaredDiffs) <= eps
}
// AddNumericStats combines derived statistics.
// Adapted from https://www.johndcook.com/blog/skewness_kurtosis/
func AddNumericStats(a, b NumericStat, countA, countB int64) NumericStat {
total := float64(countA + countB)
delta := b.Mean - a.Mean
return NumericStat{
Mean: ((a.Mean * float64(countA)) + (b.Mean * float64(countB))) / total,
SquaredDiffs: (a.SquaredDiffs + b.SquaredDiffs) +
delta*delta*float64(countA)*float64(countB)/total,
}
}
// GetScrubbedCopy returns a copy of the given SensitiveInfo with its fields redacted
// or omitted entirely. By default, fields are omitted: if a new field is
// added to the SensitiveInfo proto, it must be added here to make it to the
// reg cluster.
func (si SensitiveInfo) GetScrubbedCopy() SensitiveInfo {
output := SensitiveInfo{}
// TODO(knz): This should really use si.LastErrorRedacted, however
// this does not exist yet.
// See: https://github.com/cockroachdb/cockroach/issues/53191
output.LastErr = "<redacted>"
// Not copying over MostRecentPlanDescription until we have an algorithm to scrub plan nodes.
return output
}
// Add combines other into this TxnStats.
func (s *TxnStats) Add(other TxnStats) {
s.TxnTimeSec.Add(other.TxnTimeSec, s.TxnCount, other.TxnCount)
s.TxnCount += other.TxnCount
s.ImplicitCount += other.ImplicitCount
s.CommittedCount += other.CommittedCount
}
// Add combines other into TransactionStatistics.
func (t *TransactionStatistics) Add(other *TransactionStatistics) {
if other.MaxRetries > t.MaxRetries {
t.MaxRetries = other.MaxRetries
}
t.CommitLat.Add(other.CommitLat, t.Count, other.Count)
t.RetryLat.Add(other.RetryLat, t.Count, other.Count)
t.ServiceLat.Add(other.ServiceLat, t.Count, other.Count)
t.NumRows.Add(other.NumRows, t.Count, other.Count)
t.Count += other.Count
}
// Add combines other into this StatementStatistics.
func (s *StatementStatistics) Add(other *StatementStatistics) {
s.FirstAttemptCount += other.FirstAttemptCount
if other.MaxRetries > s.MaxRetries {
s.MaxRetries = other.MaxRetries
}
s.NumRows.Add(other.NumRows, s.Count, other.Count)
s.ParseLat.Add(other.ParseLat, s.Count, other.Count)
s.PlanLat.Add(other.PlanLat, s.Count, other.Count)
s.RunLat.Add(other.RunLat, s.Count, other.Count)
s.ServiceLat.Add(other.ServiceLat, s.Count, other.Count)
s.OverheadLat.Add(other.OverheadLat, s.Count, other.Count)
s.BytesRead.Add(other.BytesRead, s.Count, other.Count)
s.RowsRead.Add(other.RowsRead, s.Count, other.Count)
if other.SensitiveInfo.LastErr != "" {
s.SensitiveInfo.LastErr = other.SensitiveInfo.LastErr
}
if s.SensitiveInfo.MostRecentPlanTimestamp.Before(other.SensitiveInfo.MostRecentPlanTimestamp) {
s.SensitiveInfo = other.SensitiveInfo
}
s.Count += other.Count
}
// AlmostEqual compares two StatementStatistics and their contained NumericStats
// objects within an window of size eps.
func (s *StatementStatistics) AlmostEqual(other *StatementStatistics, eps float64) bool {
return s.Count == other.Count &&
s.FirstAttemptCount == other.FirstAttemptCount &&
s.MaxRetries == other.MaxRetries &&
s.NumRows.AlmostEqual(other.NumRows, eps) &&
s.ParseLat.AlmostEqual(other.ParseLat, eps) &&
s.PlanLat.AlmostEqual(other.PlanLat, eps) &&
s.RunLat.AlmostEqual(other.RunLat, eps) &&
s.ServiceLat.AlmostEqual(other.ServiceLat, eps) &&
s.OverheadLat.AlmostEqual(other.OverheadLat, eps) &&
s.SensitiveInfo.Equal(other.SensitiveInfo) &&
s.BytesRead.AlmostEqual(other.BytesRead, eps) &&
s.RowsRead.AlmostEqual(other.RowsRead, eps)
}