| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869 |
- // Copyright (c) Tailscale Inc & contributors
- // SPDX-License-Identifier: BSD-3-Clause
- package syncs
- import (
- "encoding/json"
- "strconv"
- "sync/atomic"
- "golang.org/x/sys/cpu"
- )
- // ShardedInt provides a sharded atomic int64 value that optimizes high
- // frequency (Mhz range and above) writes in highly parallel workloads.
- // The zero value is not safe for use; use [NewShardedInt].
- // ShardedInt implements the expvar.Var interface.
- type ShardedInt struct {
- sv *ShardValue[intShard]
- }
- // NewShardedInt returns a new [ShardedInt].
- func NewShardedInt() *ShardedInt {
- return &ShardedInt{
- sv: NewShardValue[intShard](),
- }
- }
- // Add adds delta to the value.
- func (m *ShardedInt) Add(delta int64) {
- m.sv.One(func(v *intShard) {
- v.Add(delta)
- })
- }
- type intShard struct {
- atomic.Int64
- _ cpu.CacheLinePad // avoid false sharing of neighboring shards
- }
- // Value returns the current value.
- func (m *ShardedInt) Value() int64 {
- var v int64
- for s := range m.sv.All {
- v += s.Load()
- }
- return v
- }
- // GetDistribution returns the current value in each shard.
- // This is intended for observability/debugging only.
- func (m *ShardedInt) GetDistribution() []int64 {
- v := make([]int64, 0, m.sv.Len())
- for s := range m.sv.All {
- v = append(v, s.Load())
- }
- return v
- }
- // String implements the expvar.Var interface
- func (m *ShardedInt) String() string {
- v, _ := json.Marshal(m.Value())
- return string(v)
- }
- // AppendText implements the encoding.TextAppender interface
- func (m *ShardedInt) AppendText(b []byte) ([]byte, error) {
- return strconv.AppendInt(b, m.Value(), 10), nil
- }
|