-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstats.go
More file actions
218 lines (204 loc) · 6.19 KB
/
Copy pathstats.go
File metadata and controls
218 lines (204 loc) · 6.19 KB
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
package bytebufferpool
import "sync/atomic"
// ClassInventory reports exact idle Backing Storage for one Bounded Capacity Class.
// RetainedCapacity excludes allocator overhead, Go heap, and process RSS.
type ClassInventory struct {
Capacity int
IdleStorageCount int64
RetainedCapacity int64
}
// ClassStats reports optional operation counters for one Capacity Class.
// Counters are loaded independently, not as one transactional snapshot.
type ClassStats struct {
Capacity int
Hits uint64
Misses uint64
Retained uint64
Dropped uint64
}
// Stats reports Pool inventory and optional operation history.
// ClassInventory and global retained totals form one exact Bounded snapshot.
// Validation Inventory is sampled separately under its own lock. Optional
// operation counters are independent loads, not a transactional snapshot.
type Stats struct {
Generation uint64
RetainedAvailable bool
RetainedStorageCount int64
RetainedCapacity int64
ClassInventory []ClassInventory
ValidationAvailable bool
ActiveRawSlices int64
ValidationTombstones int64
MaxValidationTombstones int64
CountersAvailable bool
Acquires uint64
Hits uint64
Misses uint64
Releases uint64
Retained uint64
DroppedFull uint64
DroppedOversize uint64
DroppedInvalid uint64
DroppedUnpooled uint64
DroppedStale uint64
RejectedForeign uint64
RejectedDuplicate uint64
IgnoredNil uint64
ZeroedBytes uint64
Classes []ClassStats
}
type atomicClassCounters struct {
hits atomic.Uint64
misses atomic.Uint64
retained atomic.Uint64
dropped atomic.Uint64
}
type poolCounters struct {
acquires atomic.Uint64
hits atomic.Uint64
misses atomic.Uint64
releases atomic.Uint64
retained atomic.Uint64
droppedFull atomic.Uint64
droppedOversize atomic.Uint64
droppedInvalid atomic.Uint64
droppedUnpooled atomic.Uint64
droppedStale atomic.Uint64
rejectedForeign atomic.Uint64
rejectedDuplicate atomic.Uint64
ignoredNil atomic.Uint64
zeroedBytes atomic.Uint64
classes []atomicClassCounters
capacities []int
}
func newPoolCounters(capacities []int) *poolCounters {
return &poolCounters{
classes: make([]atomicClassCounters, len(capacities)),
capacities: append([]int(nil), capacities...),
}
}
// Stats reports inventory and operations. Generation identifies the captured
// Pool epoch and is available in both modes, independently of optional counters.
// A concurrent Clear may advance the Pool after that epoch has been captured.
func (p *Pool) Stats() Stats {
generation := p.current.Load()
stats := Stats{Generation: generation.id}
if p.config.Mode == Bounded {
for _, class := range generation.boundedClasses {
class.mu.Lock()
}
stats.RetainedAvailable = true
stats.ClassInventory = make([]ClassInventory, len(generation.boundedClasses))
for i, class := range generation.boundedClasses {
count := int64(len(class.idle))
stats.ClassInventory[i] = ClassInventory{Capacity: class.size, IdleStorageCount: count, RetainedCapacity: count * int64(class.size)}
stats.RetainedStorageCount += count
stats.RetainedCapacity += count * int64(class.size)
}
for i := len(generation.boundedClasses) - 1; i >= 0; i-- {
generation.boundedClasses[i].mu.Unlock()
}
}
if p.config.ValidationEnabled {
p.validationMu.Lock()
stats.ValidationAvailable = true
stats.MaxValidationTombstones = int64(p.config.MaxValidationTombstones)
stats.ActiveRawSlices = p.activeRawSlices
stats.ValidationTombstones = p.validationTombstones
p.validationMu.Unlock()
}
if p.counters == nil {
return stats
}
counters := p.counters
stats.CountersAvailable = true
stats.Acquires = counters.acquires.Load()
stats.Hits = counters.hits.Load()
stats.Misses = counters.misses.Load()
stats.Releases = counters.releases.Load()
stats.Retained = counters.retained.Load()
stats.DroppedFull = counters.droppedFull.Load()
stats.DroppedOversize = counters.droppedOversize.Load()
stats.DroppedInvalid = counters.droppedInvalid.Load()
stats.DroppedUnpooled = counters.droppedUnpooled.Load()
stats.DroppedStale = counters.droppedStale.Load()
stats.RejectedForeign = counters.rejectedForeign.Load()
stats.RejectedDuplicate = counters.rejectedDuplicate.Load()
stats.IgnoredNil = counters.ignoredNil.Load()
stats.ZeroedBytes = counters.zeroedBytes.Load()
stats.Classes = make([]ClassStats, len(counters.classes))
for i := range counters.classes {
class := &counters.classes[i]
stats.Classes[i] = ClassStats{
Capacity: counters.capacities[i],
Hits: class.hits.Load(),
Misses: class.misses.Load(),
Retained: class.retained.Load(),
Dropped: class.dropped.Load(),
}
}
return stats
}
func (p *Pool) recordAcquire(class int, hit bool) {
if p.counters == nil {
return
}
p.counters.acquires.Add(1)
if hit {
p.counters.hits.Add(1)
if class >= 0 {
p.counters.classes[class].hits.Add(1)
}
return
}
p.counters.misses.Add(1)
if class >= 0 {
p.counters.classes[class].misses.Add(1)
}
}
func (p *Pool) recordRelease(status ReleaseStatus, class int) ReleaseStatus {
if p.counters == nil {
return status
}
p.counters.releases.Add(1)
switch status {
case Retained:
p.counters.retained.Add(1)
if class >= 0 {
p.counters.classes[class].retained.Add(1)
}
case DroppedFull:
p.counters.droppedFull.Add(1)
case DroppedOversize:
p.counters.droppedOversize.Add(1)
case DroppedInvalid:
p.counters.droppedInvalid.Add(1)
case DroppedUnpooled:
p.counters.droppedUnpooled.Add(1)
case DroppedStale:
p.counters.droppedStale.Add(1)
case RejectedForeign:
p.counters.rejectedForeign.Add(1)
case RejectedDuplicate:
p.counters.rejectedDuplicate.Add(1)
case IgnoredNil:
p.counters.ignoredNil.Add(1)
}
if status != Retained && class >= 0 {
p.counters.classes[class].dropped.Add(1)
}
return status
}
func (p *Pool) prepareLeaseRelease(buffer []byte) {
if !p.config.ZeroOnRelease {
return
}
full := buffer[:cap(buffer)]
clear(full)
p.recordZeroed(len(full))
}
func (p *Pool) recordZeroed(bytes int) {
if p.counters != nil {
p.counters.zeroedBytes.Add(uint64(bytes))
}
}