github.com/GuanceCloud/cliutils@v1.1.21/point/ptpool.go (about) 1 package point 2 3 import ( 4 "fmt" 5 sync "sync" 6 "sync/atomic" 7 8 types "github.com/gogo/protobuf/types" 9 10 p8s "github.com/prometheus/client_golang/prometheus" 11 ) 12 13 var ( 14 reservedCapacityDesc = p8s.NewDesc("pointpool_reserved_capacity", "Reserved capacity of the pool", nil, nil) 15 chanGetDesc = p8s.NewDesc("pointpool_chan_get_total", "Get count from reserved channel", nil, nil) 16 chanPutDesc = p8s.NewDesc("pointpool_chan_put_total", "Put count to reserved channel", nil, nil) 17 18 poolGetDesc = p8s.NewDesc("pointpool_pool_get_total", "Get count from reserved channel", nil, nil) 19 poolPutDesc = p8s.NewDesc("pointpool_pool_put_total", "Put count to reserved channel", nil, nil) 20 poolMallocDesc = p8s.NewDesc("pointpool_malloc_total", "New object malloc from pool", nil, nil) 21 poolEscaped = p8s.NewDesc("pointpool_escaped", "Points that not comes from pool", nil, nil) 22 ) 23 24 type PointPool interface { 25 Get() *Point 26 Put(*Point) 27 28 GetKV(k string, v any) *Field 29 PutKV(f *Field) 30 31 // For prometheus metrics. 32 p8s.Collector 33 } 34 35 var defaultPTPool PointPool 36 37 func SetPointPool(pp PointPool) { 38 defaultPTPool = pp 39 } 40 41 func GetPointPool() PointPool { 42 return defaultPTPool 43 } 44 45 func ClearPointPool() { 46 defaultPTPool = nil 47 } 48 49 func (p *Point) clear() { 50 if p.pt != nil { 51 p.pt.Name = "" 52 p.pt.Fields = p.pt.Fields[:0] 53 p.pt.Time = 0 54 p.pt.Warns = p.pt.Warns[:0] 55 p.pt.Debugs = p.pt.Debugs[:0] 56 } 57 } 58 59 func (p *Point) Reset() { 60 p.flags = 0 61 p.clear() 62 } 63 64 func emptyPoint() *Point { 65 return &Point{ 66 pt: &PBPoint{}, 67 } 68 } 69 70 func isEmptyPoint(pt *Point) bool { 71 if pt.pt != nil { 72 return pt.flags == 0 && 73 pt.pt.Name == "" && 74 len(pt.pt.Fields) == 0 && 75 len(pt.pt.Warns) == 0 && 76 len(pt.pt.Debugs) == 0 && 77 pt.pt.Time == 0 78 } else { 79 return pt.flags == 0 80 } 81 } 82 83 type reservedCapPool struct { 84 pool sync.Pool 85 86 ch chan any 87 88 poolGet, poolPut, 89 chanGet, chanPut atomic.Int64 90 } 91 92 func newReservedCapPool(capacity int64, newFn func() any) *reservedCapPool { 93 x := &reservedCapPool{ 94 pool: sync.Pool{}, 95 ch: make(chan any, capacity), 96 } 97 98 x.pool.New = newFn 99 return x 100 } 101 102 func (p *reservedCapPool) get() any { 103 select { 104 case elem := <-p.ch: 105 p.chanGet.Add(1) 106 return elem 107 default: 108 p.poolGet.Add(1) 109 return p.pool.Get() 110 } 111 } 112 113 func (p *reservedCapPool) put(x any) { 114 select { 115 case p.ch <- x: 116 p.chanPut.Add(1) 117 return 118 default: 119 p.poolPut.Add(1) 120 p.pool.Put(x) 121 } 122 } 123 124 type ReservedCapPointPool struct { 125 capacity int64 126 127 malloc, escaped atomic.Int64 128 129 ptpool, // pool for *Point 130 // other pools for various *Fields 131 fpool, // float 132 ipool, // int 133 upool, // uint 134 spool, // string 135 bpool, // bool 136 dpool, // []byte 137 apool *reservedCapPool // any 138 } 139 140 func NewReservedCapPointPool(capacity int64) PointPool { 141 p := &ReservedCapPointPool{ 142 capacity: capacity, 143 } 144 145 p.ptpool = newReservedCapPool(capacity, func() any { 146 p.malloc.Add(1) 147 return emptyPoint() 148 }) 149 150 p.fpool = newReservedCapPool(capacity, func() any { 151 p.malloc.Add(1) 152 return &Field{Val: &Field_F{}} 153 }) 154 155 p.ipool = newReservedCapPool(capacity, func() any { 156 p.malloc.Add(1) 157 return &Field{Val: &Field_I{}} 158 }) 159 160 p.upool = newReservedCapPool(capacity, func() any { 161 p.malloc.Add(1) 162 return &Field{Val: &Field_U{}} 163 }) 164 165 p.spool = newReservedCapPool(capacity, func() any { 166 p.malloc.Add(1) 167 return &Field{Val: &Field_S{}} 168 }) 169 170 p.bpool = newReservedCapPool(capacity, func() any { 171 p.malloc.Add(1) 172 return &Field{Val: &Field_B{}} 173 }) 174 175 p.dpool = newReservedCapPool(capacity, func() any { 176 p.malloc.Add(1) 177 return &Field{Val: &Field_D{}} 178 }) 179 180 p.apool = newReservedCapPool(capacity, func() any { 181 p.malloc.Add(1) 182 return &Field{Val: &Field_A{}} 183 }) 184 185 return p 186 } 187 188 func (cpp *ReservedCapPointPool) Get() *Point { 189 return cpp.ptpool.get().(*Point) 190 } 191 192 func (cpp *ReservedCapPointPool) Put(p *Point) { 193 if !p.HasFlag(Ppooled) { 194 cpp.escaped.Add(1) 195 return 196 } 197 198 for _, f := range p.KVs() { 199 cpp.PutKV(f) 200 } 201 202 p.Reset() 203 cpp.ptpool.put(p) 204 } 205 206 func (cpp *ReservedCapPointPool) GetKV(k string, v any) *Field { 207 var ( 208 kv *Field 209 arr *types.Any 210 err error 211 ) 212 213 switch x := v.(type) { 214 case int8: 215 kv = cpp.ipool.get().(*Field) 216 kv.Val.(*Field_I).I = int64(x) 217 case uint8: 218 kv = cpp.upool.get().(*Field) 219 kv.Val.(*Field_U).U = uint64(x) 220 case int16: 221 kv = cpp.ipool.get().(*Field) 222 kv.Val.(*Field_I).I = int64(x) 223 case uint16: 224 kv = cpp.upool.get().(*Field) 225 kv.Val.(*Field_U).U = uint64(x) 226 case int32: 227 kv = cpp.ipool.get().(*Field) 228 kv.Val.(*Field_I).I = int64(x) 229 case uint32: 230 kv = cpp.upool.get().(*Field) 231 kv.Val.(*Field_U).U = uint64(x) 232 case int: 233 kv = cpp.ipool.get().(*Field) 234 kv.Val.(*Field_I).I = int64(x) 235 case uint: 236 kv = cpp.upool.get().(*Field) 237 kv.Val.(*Field_U).U = uint64(x) 238 case int64: 239 kv = cpp.ipool.get().(*Field) 240 kv.Val.(*Field_I).I = x 241 case uint64: 242 kv = cpp.upool.get().(*Field) 243 kv.Val.(*Field_U).U = x 244 case float64: 245 kv = cpp.fpool.get().(*Field) 246 kv.Val.(*Field_F).F = x 247 case float32: 248 kv = cpp.fpool.get().(*Field) 249 kv.Val.(*Field_F).F = float64(x) 250 case string: 251 kv = cpp.spool.get().(*Field) 252 kv.Val.(*Field_S).S = x // XXX: should we make a clone of x? 253 case []byte: 254 kv = cpp.dpool.get().(*Field) 255 kv.Val.(*Field_D).D = append(kv.Val.(*Field_D).D, x...) // deep copied 256 case bool: 257 kv = cpp.bpool.get().(*Field) 258 kv.Val.(*Field_B).B = x 259 260 case *types.Any: 261 kv = cpp.apool.get().(*Field) 262 kv.Val.(*Field_A).A = x 263 264 // following are array types 265 case []int8: 266 kv = cpp.apool.get().(*Field) 267 arr, err = NewIntArray(x...) 268 case []int16: 269 kv = cpp.apool.get().(*Field) 270 arr, err = NewIntArray(x...) 271 case []int32: 272 kv = cpp.apool.get().(*Field) 273 arr, err = NewIntArray(x...) 274 case []int64: 275 kv = cpp.apool.get().(*Field) 276 arr, err = NewIntArray(x...) 277 case []int: 278 kv = cpp.apool.get().(*Field) 279 arr, err = NewIntArray(x...) 280 case []uint16: 281 kv = cpp.apool.get().(*Field) 282 arr, err = NewUintArray(x...) 283 case []uint32: 284 kv = cpp.apool.get().(*Field) 285 arr, err = NewUintArray(x...) 286 case []uint64: 287 kv = cpp.apool.get().(*Field) 288 arr, err = NewUintArray(x...) 289 290 case []uint: 291 kv = cpp.apool.get().(*Field) 292 arr, err = NewUintArray(x...) 293 294 case []float32: 295 kv = cpp.apool.get().(*Field) 296 arr, err = NewFloatArray(x...) 297 298 case []float64: 299 kv = cpp.apool.get().(*Field) 300 arr, err = NewFloatArray(x...) 301 302 case []string: 303 kv = cpp.apool.get().(*Field) 304 arr, err = NewStringArray(x...) 305 306 case []bool: 307 kv = cpp.apool.get().(*Field) 308 arr, err = NewBoolArray(x...) 309 310 case [][]byte: 311 kv = cpp.apool.get().(*Field) 312 arr, err = NewBytesArray(x...) 313 314 case []any: 315 kv = cpp.apool.get().(*Field) 316 arr, err = NewAnyArray(x...) 317 318 default: // for nil or other types 319 return &Field{ 320 Key: k, 321 Val: newVal(v), 322 } 323 } 324 325 // there are array types. 326 if arr != nil && err == nil { 327 kv.Val.(*Field_A).A = arr 328 } 329 330 if kv != nil { 331 kv.Key = k 332 } 333 334 return kv 335 } 336 337 func (cpp *ReservedCapPointPool) PutKV(f *Field) { 338 f = resetKV(clearKV(f)) 339 340 switch f.Val.(type) { 341 case *Field_A: 342 cpp.apool.put(f) 343 case *Field_B: 344 cpp.bpool.put(f) 345 case *Field_D: 346 cpp.dpool.put(f) 347 case *Field_F: 348 cpp.fpool.put(f) 349 case *Field_I: 350 cpp.ipool.put(f) 351 case *Field_S: 352 cpp.spool.put(f) 353 case *Field_U: 354 cpp.upool.put(f) 355 } 356 } 357 358 func (cpp *ReservedCapPointPool) String() string { 359 return fmt.Sprintf("chanGet: %d, chanPut: %d, poolGet: %d, pollPut: %d, allocs: %d", 360 cpp.chanGet(), cpp.chanPut(), cpp.poolGet(), cpp.poolPut(), cpp.malloc.Load()) 361 } 362 363 func (cpp *ReservedCapPointPool) chanGet() int64 { 364 return cpp.apool.chanGet.Load() + 365 cpp.bpool.chanGet.Load() + 366 cpp.dpool.chanGet.Load() + 367 cpp.fpool.chanGet.Load() + 368 cpp.ipool.chanGet.Load() + 369 cpp.spool.chanGet.Load() + 370 cpp.upool.chanGet.Load() 371 } 372 373 func (cpp *ReservedCapPointPool) chanPut() int64 { 374 return cpp.apool.chanGet.Load() + 375 cpp.bpool.chanPut.Load() + 376 cpp.dpool.chanPut.Load() + 377 cpp.fpool.chanPut.Load() + 378 cpp.ipool.chanPut.Load() + 379 cpp.spool.chanPut.Load() + 380 cpp.upool.chanPut.Load() 381 } 382 383 func (cpp *ReservedCapPointPool) poolGet() int64 { 384 return cpp.apool.chanGet.Load() + 385 cpp.bpool.poolGet.Load() + 386 cpp.dpool.poolGet.Load() + 387 cpp.fpool.poolGet.Load() + 388 cpp.ipool.poolGet.Load() + 389 cpp.spool.poolGet.Load() + 390 cpp.upool.poolGet.Load() 391 } 392 393 func (cpp *ReservedCapPointPool) poolPut() int64 { 394 return cpp.apool.chanGet.Load() + 395 cpp.bpool.poolPut.Load() + 396 cpp.dpool.poolPut.Load() + 397 cpp.fpool.poolPut.Load() + 398 cpp.ipool.poolPut.Load() + 399 cpp.spool.poolPut.Load() + 400 cpp.upool.poolPut.Load() 401 } 402 403 func (cpp *ReservedCapPointPool) Describe(ch chan<- *p8s.Desc) { p8s.DescribeByCollect(cpp, ch) } 404 func (cpp *ReservedCapPointPool) Collect(ch chan<- p8s.Metric) { 405 ch <- p8s.MustNewConstMetric(chanGetDesc, p8s.CounterValue, float64(cpp.chanGet())) 406 ch <- p8s.MustNewConstMetric(chanPutDesc, p8s.CounterValue, float64(cpp.chanPut())) 407 ch <- p8s.MustNewConstMetric(poolGetDesc, p8s.CounterValue, float64(cpp.poolGet())) 408 ch <- p8s.MustNewConstMetric(poolPutDesc, p8s.CounterValue, float64(cpp.poolPut())) 409 410 ch <- p8s.MustNewConstMetric(reservedCapacityDesc, p8s.CounterValue, float64(cpp.capacity)) 411 ch <- p8s.MustNewConstMetric(poolMallocDesc, p8s.CounterValue, float64(cpp.malloc.Load())) 412 ch <- p8s.MustNewConstMetric(poolEscaped, p8s.CounterValue, float64(cpp.escaped.Load())) 413 }