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  }