mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 03:30:37 +00:00
Remove unused metrics and out of date versions (#8109)
ergon/metrics contains a lot of unused types - the pull is removing them prior to rationalizing between Prometheus and Victoria Metrics types. It also have upgrades of golang-lru + sets types to v2 when possible.
This commit is contained in:
parent
5fbb9e2f87
commit
e81852320c
@ -24,7 +24,7 @@ import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set"
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
"github.com/holiman/uint256"
|
||||
"github.com/ledgerwatch/erigon-lib/chain"
|
||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||
@ -149,9 +149,9 @@ func (ethash *Ethash) VerifyUncles(chain consensus.ChainReader, header *types.He
|
||||
return nil
|
||||
}
|
||||
|
||||
func getUncles(chain consensus.ChainReader, header *types.Header) (mapset.Set, map[libcommon.Hash]*types.Header) {
|
||||
func getUncles(chain consensus.ChainReader, header *types.Header) (mapset.Set[libcommon.Hash], map[libcommon.Hash]*types.Header) {
|
||||
// Gather the set of past uncles and ancestors
|
||||
uncles, ancestors := mapset.NewSet(), make(map[libcommon.Hash]*types.Header)
|
||||
uncles, ancestors := mapset.NewSet[libcommon.Hash](), make(map[libcommon.Hash]*types.Header)
|
||||
|
||||
number, parent := header.Number.Uint64()-1, header.ParentHash
|
||||
for i := 0; i < 7; i++ {
|
||||
@ -178,7 +178,7 @@ func getUncles(chain consensus.ChainReader, header *types.Header) (mapset.Set, m
|
||||
return uncles, ancestors
|
||||
}
|
||||
|
||||
func (ethash *Ethash) VerifyUncle(chain consensus.ChainHeaderReader, header *types.Header, uncle *types.Header, uncles mapset.Set, ancestors map[libcommon.Hash]*types.Header, seal bool) error {
|
||||
func (ethash *Ethash) VerifyUncle(chain consensus.ChainHeaderReader, header *types.Header, uncle *types.Header, uncles mapset.Set[libcommon.Hash], ancestors map[libcommon.Hash]*types.Header, seal bool) error {
|
||||
// Make sure every uncle is rewarded only once
|
||||
hash := uncle.Hash()
|
||||
if uncles.Contains(hash) {
|
||||
|
@ -32,13 +32,12 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/edsrzf/mmap-go"
|
||||
"github.com/hashicorp/golang-lru/simplelru"
|
||||
"github.com/hashicorp/golang-lru/v2/simplelru"
|
||||
"github.com/ledgerwatch/erigon/consensus/ethash/ethashcfg"
|
||||
|
||||
"github.com/ledgerwatch/erigon/common/debug"
|
||||
cmath "github.com/ledgerwatch/erigon/common/math"
|
||||
"github.com/ledgerwatch/erigon/consensus"
|
||||
"github.com/ledgerwatch/erigon/metrics"
|
||||
"github.com/ledgerwatch/erigon/rpc"
|
||||
"github.com/ledgerwatch/log/v3"
|
||||
)
|
||||
@ -183,7 +182,7 @@ type lru struct {
|
||||
mu sync.Mutex
|
||||
// Items are kept in a LRU cache, but there is a special case:
|
||||
// We always keep an item for (highest seen epoch) + 1 as the 'future item'.
|
||||
cache *simplelru.LRU
|
||||
cache *simplelru.LRU[uint64, any]
|
||||
future uint64
|
||||
futureItem interface{}
|
||||
}
|
||||
@ -194,7 +193,7 @@ func newlru(what string, maxItems int, new func(epoch uint64) interface{}) *lru
|
||||
if maxItems <= 0 {
|
||||
maxItems = 1
|
||||
}
|
||||
cache, _ := simplelru.NewLRU(maxItems, func(key, value interface{}) {
|
||||
cache, _ := simplelru.NewLRU[uint64, any](maxItems, func(key uint64, value interface{}) {
|
||||
log.Trace("Evicted ethash "+what, "epoch", key)
|
||||
})
|
||||
return &lru{what: what, new: new, cache: cache}
|
||||
@ -410,8 +409,8 @@ type Ethash struct {
|
||||
datasets *lru // In memory datasets to avoid regenerating too often
|
||||
|
||||
// Mining related fields
|
||||
rand *rand.Rand // Properly seeded random source for nonces
|
||||
hashrate metrics.Meter // Meter tracking the average hashrate
|
||||
rand *rand.Rand // Properly seeded random source for nonces
|
||||
hashrate *hashRateMeter // Meter tracking the average hashrate
|
||||
remote *remoteSealer
|
||||
|
||||
// The fields below are hooks for testing
|
||||
@ -439,7 +438,7 @@ func New(config ethashcfg.Config, notify []string, noverify bool) *Ethash {
|
||||
config: config,
|
||||
caches: newlru("cache", config.CachesInMem, newCache),
|
||||
datasets: newlru("dataset", config.DatasetsInMem, newDataset),
|
||||
hashrate: metrics.NewMeterForced(),
|
||||
hashrate: newHashRateMeter(),
|
||||
}
|
||||
if config.PowMode == ethashcfg.ModeShared {
|
||||
ethash.shared = GetSharedEthash()
|
||||
@ -534,7 +533,7 @@ func (ethash *Ethash) dataset(block uint64, async bool) *dataset {
|
||||
func (ethash *Ethash) Hashrate() float64 {
|
||||
// Short circuit if we are run the ethash in normal/test mode.
|
||||
if (ethash.config.PowMode != ethashcfg.ModeNormal && ethash.config.PowMode != ethashcfg.ModeTest) || ethash.remote == nil {
|
||||
return ethash.hashrate.Rate1()
|
||||
return ethash.hashrate.Rate()
|
||||
}
|
||||
var res = make(chan uint64, 1)
|
||||
|
||||
@ -542,11 +541,11 @@ func (ethash *Ethash) Hashrate() float64 {
|
||||
case ethash.remote.fetchRateCh <- res:
|
||||
case <-ethash.remote.exitCh:
|
||||
// Return local hashrate only if ethash is stopped.
|
||||
return ethash.hashrate.Rate1()
|
||||
return ethash.hashrate.Rate()
|
||||
}
|
||||
|
||||
// Gather total submitted hash rate of remote sealers.
|
||||
return ethash.hashrate.Rate1() + float64(<-res)
|
||||
return ethash.hashrate.Rate() + float64(<-res)
|
||||
}
|
||||
|
||||
// APIs implements consensus.Engine, returning the user facing RPC APIs.
|
||||
|
@ -3,7 +3,7 @@ package ethash
|
||||
import (
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set"
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon/consensus/ethash/ethashcfg"
|
||||
"github.com/ledgerwatch/log/v3"
|
||||
@ -87,7 +87,7 @@ func (f *FakeEthash) VerifyUncles(chain consensus.ChainReader, header *types.Hea
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeEthash) VerifyUncle(chain consensus.ChainHeaderReader, block *types.Header, uncle *types.Header, uncles mapset.Set, ancestors map[libcommon.Hash]*types.Header, seal bool) error {
|
||||
func (f *FakeEthash) VerifyUncle(chain consensus.ChainHeaderReader, block *types.Header, uncle *types.Header, uncles mapset.Set[libcommon.Hash], ancestors map[libcommon.Hash]*types.Header, seal bool) error {
|
||||
err := f.Ethash.VerifyUncle(chain, block, uncle, uncles, ancestors, false)
|
||||
if err != nil {
|
||||
return err
|
||||
|
193
consensus/ethash/meter.go
Normal file
193
consensus/ethash/meter.go
Normal file
@ -0,0 +1,193 @@
|
||||
package ethash
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ledgerwatch/erigon/common/debug"
|
||||
)
|
||||
|
||||
func newHashRateMeter() *hashRateMeter {
|
||||
m := newMeter()
|
||||
arbiter.mu.Lock()
|
||||
defer arbiter.mu.Unlock()
|
||||
arbiter.meters[m] = struct{}{}
|
||||
if !arbiter.started {
|
||||
arbiter.started = true
|
||||
go arbiter.tick()
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// meterSnapshot is a read-only copy of another Meter.
|
||||
type meterSnapshot struct {
|
||||
// WARNING: The `temp` field is accessed atomically.
|
||||
// On 32 bit platforms, only 64-bit aligned fields can be atomic. The struct is
|
||||
// guaranteed to be so aligned, so take advantage of that. For more information,
|
||||
// see https://golang.org/pkg/sync/atomic/#pkg-note-BUG.
|
||||
temp int64
|
||||
count int64
|
||||
rate float64
|
||||
}
|
||||
|
||||
// Count returns the count of events at the time the snapshot was taken.
|
||||
func (m *meterSnapshot) Count() int64 { return m.count }
|
||||
|
||||
// Mark panics.
|
||||
func (*meterSnapshot) Mark(n int64) {
|
||||
panic("Mark called on a MeterSnapshot")
|
||||
}
|
||||
|
||||
// Rate1 returns the one-minute moving average rate of events per second at the
|
||||
// time the snapshot was taken.
|
||||
func (m *meterSnapshot) Rate() float64 { return m.rate }
|
||||
|
||||
// Stop is a no-op.
|
||||
func (m *meterSnapshot) Stop() {}
|
||||
|
||||
// StandardMeter is the standard implementation of a Meter.
|
||||
type hashRateMeter struct {
|
||||
lock sync.RWMutex
|
||||
snapshot *meterSnapshot
|
||||
a1 *ewma
|
||||
startTime time.Time
|
||||
stopped uint32
|
||||
}
|
||||
|
||||
func newMeter() *hashRateMeter {
|
||||
return &hashRateMeter{
|
||||
snapshot: &meterSnapshot{},
|
||||
a1: &ewma{alpha: 1 - math.Exp(-5.0/60.0/1)},
|
||||
startTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// Stop stops the meter, Mark() will be a no-op if you use it after being stopped.
|
||||
func (m *hashRateMeter) Stop() {
|
||||
stopped := atomic.SwapUint32(&m.stopped, 1)
|
||||
if stopped != 1 {
|
||||
arbiter.mu.Lock()
|
||||
delete(arbiter.meters, m)
|
||||
arbiter.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Count returns the number of events recorded.
|
||||
// It updates the meter to be as accurate as possible
|
||||
func (m *hashRateMeter) Count() int64 {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
m.updateMeter()
|
||||
return m.snapshot.count
|
||||
}
|
||||
|
||||
// Mark records the occurrence of n events.
|
||||
func (m *hashRateMeter) Mark(n int64) {
|
||||
m.lock.Lock()
|
||||
m.snapshot.temp = n
|
||||
m.lock.Unlock()
|
||||
}
|
||||
|
||||
// Rate returns the one-minute moving average rate of events per second.
|
||||
func (m *hashRateMeter) Rate() float64 {
|
||||
m.lock.RLock()
|
||||
defer m.lock.RUnlock()
|
||||
return m.snapshot.rate
|
||||
}
|
||||
|
||||
// Snapshot returns a read-only copy of the meter.
|
||||
func (m *hashRateMeter) Snapshot() *meterSnapshot {
|
||||
m.lock.RLock()
|
||||
snapshot := *m.snapshot
|
||||
m.lock.RUnlock()
|
||||
return &snapshot
|
||||
}
|
||||
|
||||
func (m *hashRateMeter) updateSnapshot() {
|
||||
// should run with write lock held on m.lock
|
||||
snapshot := m.snapshot
|
||||
snapshot.rate = m.a1.Rate()
|
||||
}
|
||||
|
||||
func (m *hashRateMeter) updateMeter() {
|
||||
// should only run with write lock held on m.lock
|
||||
n := atomic.SwapInt64(&m.snapshot.temp, 0)
|
||||
m.snapshot.count += n
|
||||
m.a1.Update(n)
|
||||
}
|
||||
|
||||
func (m *hashRateMeter) tick() {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
m.updateMeter()
|
||||
m.a1.Tick()
|
||||
m.updateSnapshot()
|
||||
}
|
||||
|
||||
// meterArbiter ticks meters every 5s from a single goroutine.
|
||||
// meters are references in a set for future stopping.
|
||||
type meterArbiter struct {
|
||||
mu sync.RWMutex
|
||||
started bool
|
||||
meters map[*hashRateMeter]struct{}
|
||||
ticker *time.Ticker
|
||||
}
|
||||
|
||||
var arbiter = meterArbiter{ticker: time.NewTicker(5 * time.Second), meters: make(map[*hashRateMeter]struct{})}
|
||||
|
||||
// Ticks meters on the scheduled interval
|
||||
func (ma *meterArbiter) tick() {
|
||||
defer debug.LogPanic()
|
||||
for range ma.ticker.C {
|
||||
ma.tickMeters()
|
||||
}
|
||||
}
|
||||
|
||||
func (ma *meterArbiter) tickMeters() {
|
||||
ma.mu.RLock()
|
||||
defer ma.mu.RUnlock()
|
||||
for meter := range ma.meters {
|
||||
meter.tick()
|
||||
}
|
||||
}
|
||||
|
||||
// ewma is the standard implementation of an EWMA and tracks the number
|
||||
// of uncounted events and processes them on each tick. It uses the
|
||||
// sync/atomic package to manage uncounted events.
|
||||
type ewma struct {
|
||||
uncounted int64 // /!\ this should be the first member to ensure 64-bit alignment
|
||||
alpha float64
|
||||
rate float64
|
||||
init bool
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// Rate returns the moving average rate of events per second.
|
||||
func (a *ewma) Rate() float64 {
|
||||
a.mutex.Lock()
|
||||
defer a.mutex.Unlock()
|
||||
return a.rate * float64(time.Second)
|
||||
}
|
||||
|
||||
// Tick ticks the clock to update the moving average. It assumes it is called
|
||||
// every five seconds.
|
||||
func (a *ewma) Tick() {
|
||||
count := atomic.LoadInt64(&a.uncounted)
|
||||
atomic.AddInt64(&a.uncounted, -count)
|
||||
instantRate := float64(count) / float64(5*time.Second)
|
||||
a.mutex.Lock()
|
||||
defer a.mutex.Unlock()
|
||||
if a.init {
|
||||
a.rate += a.alpha * (instantRate - a.rate)
|
||||
} else {
|
||||
a.init = true
|
||||
a.rate = instantRate
|
||||
}
|
||||
}
|
||||
|
||||
// Update adds n uncounted events.
|
||||
func (a *ewma) Update(n int64) {
|
||||
atomic.AddInt64(&a.uncounted, n)
|
||||
}
|
@ -7,7 +7,7 @@ import (
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set"
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
"github.com/ledgerwatch/erigon-lib/chain"
|
||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon/turbo/services"
|
||||
@ -159,15 +159,15 @@ func SpawnMiningCreateBlockStage(s *StageState, tx kv.RwTx, cfg MiningCreateBloc
|
||||
|
||||
type envT struct {
|
||||
signer *types.Signer
|
||||
ancestors mapset.Set // ancestor set (used for checking uncle parent validity)
|
||||
family mapset.Set // family set (used for checking uncle invalidity)
|
||||
uncles mapset.Set // uncle set
|
||||
ancestors mapset.Set[libcommon.Hash] // ancestor set (used for checking uncle parent validity)
|
||||
family mapset.Set[libcommon.Hash] // family set (used for checking uncle invalidity)
|
||||
uncles mapset.Set[libcommon.Hash] // uncle set
|
||||
}
|
||||
env := &envT{
|
||||
signer: types.MakeSigner(&cfg.chainConfig, blockNum, timestamp),
|
||||
ancestors: mapset.NewSet(),
|
||||
family: mapset.NewSet(),
|
||||
uncles: mapset.NewSet(),
|
||||
ancestors: mapset.NewSet[libcommon.Hash](),
|
||||
family: mapset.NewSet[libcommon.Hash](),
|
||||
uncles: mapset.NewSet[libcommon.Hash](),
|
||||
}
|
||||
|
||||
header := core.MakeEmptyHeader(parent, &cfg.chainConfig, timestamp, &cfg.miner.MiningConfig.GasLimit)
|
||||
@ -211,14 +211,9 @@ func SpawnMiningCreateBlockStage(s *StageState, tx kv.RwTx, cfg MiningCreateBloc
|
||||
}
|
||||
|
||||
// analog of miner.Worker.updateSnapshot
|
||||
var makeUncles = func(proposedUncles mapset.Set) []*types.Header {
|
||||
var makeUncles = func(proposedUncles mapset.Set[libcommon.Hash]) []*types.Header {
|
||||
var uncles []*types.Header
|
||||
proposedUncles.Each(func(item interface{}) bool {
|
||||
hash, ok := item.(libcommon.Hash)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
proposedUncles.Each(func(hash libcommon.Hash) bool {
|
||||
uncle, exist := localUncles[hash]
|
||||
if !exist {
|
||||
uncle, exist = remoteUncles[hash]
|
||||
|
1
go.mod
1
go.mod
@ -45,7 +45,6 @@ require (
|
||||
github.com/google/gofuzz v1.2.0
|
||||
github.com/gorilla/websocket v1.5.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
|
||||
github.com/hashicorp/golang-lru/arc/v2 v2.0.4
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.4
|
||||
github.com/holiman/uint256 v1.2.3
|
||||
|
2
go.sum
2
go.sum
@ -421,8 +421,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vb
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hashicorp/golang-lru/arc/v2 v2.0.4 h1:+tHnVSaabYlClRqUq4/+xzeyy9nAf8ju/JJsb4KTNBc=
|
||||
github.com/hashicorp/golang-lru/arc/v2 v2.0.4/go.mod h1:rbQ1sKlUmbE1QbWxZbqtbpw8frA8ecNEhI0cQBxYtaU=
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.4 h1:7GHuZcgid37q8o5i3QI9KMT4nCWQQ3Kx3Ov6bb9MfK0=
|
||||
|
@ -1 +0,0 @@
|
||||
This repo has been forked from https://github.com/rcrowley/go-metrics at commit e181e09
|
@ -1,29 +0,0 @@
|
||||
Copyright 2012 Richard Crowley. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY RICHARD CROWLEY ``AS IS'' AND ANY EXPRESS
|
||||
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL RICHARD CROWLEY OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation
|
||||
are those of the authors and should not be interpreted as representing
|
||||
official policies, either expressed or implied, of Richard Crowley.
|
@ -1,10 +0,0 @@
|
||||
package metrics
|
||||
|
||||
// Counters hold an int64 value that can be incremented and decremented.
|
||||
type Counter interface {
|
||||
Clear()
|
||||
Count() int64
|
||||
Dec(int64)
|
||||
Inc(int64)
|
||||
Snapshot() Counter
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestDebugGCStatsBlocking(t *testing.T) {
|
||||
if g := runtime.GOMAXPROCS(0); g < 2 {
|
||||
t.Skipf("skipping TestDebugGCMemStatsBlocking with GOMAXPROCS=%d\n", g)
|
||||
return
|
||||
}
|
||||
ch := make(chan int)
|
||||
go testDebugGCStatsBlocking(ch)
|
||||
var gcStats debug.GCStats
|
||||
t0 := time.Now()
|
||||
debug.ReadGCStats(&gcStats)
|
||||
t1 := time.Now()
|
||||
t.Log("i++ during debug.ReadGCStats:", <-ch)
|
||||
go testDebugGCStatsBlocking(ch)
|
||||
d := t1.Sub(t0)
|
||||
t.Log(d)
|
||||
time.Sleep(d)
|
||||
t.Log("i++ during time.Sleep:", <-ch)
|
||||
}
|
||||
|
||||
func testDebugGCStatsBlocking(ch chan int) {
|
||||
i := 0
|
||||
for {
|
||||
select {
|
||||
case ch <- i:
|
||||
return
|
||||
default:
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
package metrics
|
||||
|
||||
const epsilon = 0.0000000000000001
|
116
metrics/ewma.go
116
metrics/ewma.go
@ -1,116 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
// EWMAs continuously calculate an exponentially-weighted moving average
|
||||
// based on an outside source of clock ticks.
|
||||
type EWMA interface {
|
||||
Rate() float64
|
||||
Snapshot() EWMA
|
||||
Tick()
|
||||
Update(int64)
|
||||
}
|
||||
|
||||
// NewEWMA constructs a new EWMA with the given alpha.
|
||||
func NewEWMA(alpha float64) EWMA {
|
||||
return &StandardEWMA{alpha: alpha}
|
||||
}
|
||||
|
||||
// NewEWMA1 constructs a new EWMA for a one-minute moving average.
|
||||
func NewEWMA1() EWMA {
|
||||
return NewEWMA(1 - math.Exp(-5.0/60.0/1))
|
||||
}
|
||||
|
||||
// NewEWMA5 constructs a new EWMA for a five-minute moving average.
|
||||
func NewEWMA5() EWMA {
|
||||
return NewEWMA(1 - math.Exp(-5.0/60.0/5))
|
||||
}
|
||||
|
||||
// NewEWMA15 constructs a new EWMA for a fifteen-minute moving average.
|
||||
func NewEWMA15() EWMA {
|
||||
return NewEWMA(1 - math.Exp(-5.0/60.0/15))
|
||||
}
|
||||
|
||||
// EWMASnapshot is a read-only copy of another EWMA.
|
||||
type EWMASnapshot float64
|
||||
|
||||
// Rate returns the rate of events per second at the time the snapshot was
|
||||
// taken.
|
||||
func (a EWMASnapshot) Rate() float64 { return float64(a) }
|
||||
|
||||
// Snapshot returns the snapshot.
|
||||
func (a EWMASnapshot) Snapshot() EWMA { return a }
|
||||
|
||||
// Tick panics.
|
||||
func (EWMASnapshot) Tick() {
|
||||
panic("Tick called on an EWMASnapshot")
|
||||
}
|
||||
|
||||
// Update panics.
|
||||
func (EWMASnapshot) Update(int64) {
|
||||
panic("Update called on an EWMASnapshot")
|
||||
}
|
||||
|
||||
// NilEWMA is a no-op EWMA.
|
||||
type NilEWMA struct{}
|
||||
|
||||
// Rate is a no-op.
|
||||
func (NilEWMA) Rate() float64 { return 0.0 }
|
||||
|
||||
// Snapshot is a no-op.
|
||||
func (NilEWMA) Snapshot() EWMA { return NilEWMA{} }
|
||||
|
||||
// Tick is a no-op.
|
||||
func (NilEWMA) Tick() {}
|
||||
|
||||
// Update is a no-op.
|
||||
func (NilEWMA) Update(n int64) {}
|
||||
|
||||
// StandardEWMA is the standard implementation of an EWMA and tracks the number
|
||||
// of uncounted events and processes them on each tick. It uses the
|
||||
// sync/atomic package to manage uncounted events.
|
||||
type StandardEWMA struct {
|
||||
uncounted int64 // /!\ this should be the first member to ensure 64-bit alignment
|
||||
alpha float64
|
||||
rate float64
|
||||
init bool
|
||||
mutex sync.Mutex
|
||||
}
|
||||
|
||||
// Rate returns the moving average rate of events per second.
|
||||
func (a *StandardEWMA) Rate() float64 {
|
||||
a.mutex.Lock()
|
||||
defer a.mutex.Unlock()
|
||||
return a.rate * float64(time.Second)
|
||||
}
|
||||
|
||||
// Snapshot returns a read-only copy of the EWMA.
|
||||
func (a *StandardEWMA) Snapshot() EWMA {
|
||||
return EWMASnapshot(a.Rate())
|
||||
}
|
||||
|
||||
// Tick ticks the clock to update the moving average. It assumes it is called
|
||||
// every five seconds.
|
||||
func (a *StandardEWMA) Tick() {
|
||||
count := atomic.LoadInt64(&a.uncounted)
|
||||
atomic.AddInt64(&a.uncounted, -count)
|
||||
instantRate := float64(count) / float64(5*time.Second)
|
||||
a.mutex.Lock()
|
||||
defer a.mutex.Unlock()
|
||||
if a.init {
|
||||
a.rate += a.alpha * (instantRate - a.rate)
|
||||
} else {
|
||||
a.init = true
|
||||
a.rate = instantRate
|
||||
}
|
||||
}
|
||||
|
||||
// Update adds n uncounted events.
|
||||
func (a *StandardEWMA) Update(n int64) {
|
||||
atomic.AddInt64(&a.uncounted, n)
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkEWMA(b *testing.B) {
|
||||
a := NewEWMA1()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
a.Update(1)
|
||||
a.Tick()
|
||||
}
|
||||
}
|
||||
|
||||
func TestEWMA1(t *testing.T) {
|
||||
a := NewEWMA1()
|
||||
a.Update(3)
|
||||
a.Tick()
|
||||
if rate := a.Rate(); math.Abs(0.6-rate) > epsilon {
|
||||
t.Errorf("initial a.Rate(): 0.6 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.22072766470286553-rate) > epsilon {
|
||||
t.Errorf("1 minute a.Rate(): 0.22072766470286553 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.08120116994196772-rate) > epsilon {
|
||||
t.Errorf("2 minute a.Rate(): 0.08120116994196772 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.029872241020718428-rate) > epsilon {
|
||||
t.Errorf("3 minute a.Rate(): 0.029872241020718428 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.01098938333324054-rate) > epsilon {
|
||||
t.Errorf("4 minute a.Rate(): 0.01098938333324054 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.004042768199451294-rate) > epsilon {
|
||||
t.Errorf("5 minute a.Rate(): 0.004042768199451294 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.0014872513059998212-rate) > epsilon {
|
||||
t.Errorf("6 minute a.Rate(): 0.0014872513059998212 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.0005471291793327122-rate) > epsilon {
|
||||
t.Errorf("7 minute a.Rate(): 0.0005471291793327122 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.00020127757674150815-rate) > epsilon {
|
||||
t.Errorf("8 minute a.Rate(): 0.00020127757674150815 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(7.404588245200814e-05-rate) > epsilon {
|
||||
t.Errorf("9 minute a.Rate(): 7.404588245200814e-05 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(2.7239957857491083e-05-rate) > epsilon {
|
||||
t.Errorf("10 minute a.Rate(): 2.7239957857491083e-05 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(1.0021020474147462e-05-rate) > epsilon {
|
||||
t.Errorf("11 minute a.Rate(): 1.0021020474147462e-05 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(3.6865274119969525e-06-rate) > epsilon {
|
||||
t.Errorf("12 minute a.Rate(): 3.6865274119969525e-06 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(1.3561976441886433e-06-rate) > epsilon {
|
||||
t.Errorf("13 minute a.Rate(): 1.3561976441886433e-06 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(4.989172314621449e-07-rate) > epsilon {
|
||||
t.Errorf("14 minute a.Rate(): 4.989172314621449e-07 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(1.8354139230109722e-07-rate) > epsilon {
|
||||
t.Errorf("15 minute a.Rate(): 1.8354139230109722e-07 != %v\n", rate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEWMA5(t *testing.T) {
|
||||
a := NewEWMA5()
|
||||
a.Update(3)
|
||||
a.Tick()
|
||||
if rate := a.Rate(); math.Abs(0.6-rate) > epsilon {
|
||||
t.Errorf("initial a.Rate(): 0.6 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.49123845184678905-rate) > epsilon {
|
||||
t.Errorf("1 minute a.Rate(): 0.49123845184678905 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.4021920276213837-rate) > epsilon {
|
||||
t.Errorf("2 minute a.Rate(): 0.4021920276213837 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.32928698165641596-rate) > epsilon {
|
||||
t.Errorf("3 minute a.Rate(): 0.32928698165641596 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.269597378470333-rate) > epsilon {
|
||||
t.Errorf("4 minute a.Rate(): 0.269597378470333 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.2207276647028654-rate) > epsilon {
|
||||
t.Errorf("5 minute a.Rate(): 0.2207276647028654 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.18071652714732128-rate) > epsilon {
|
||||
t.Errorf("6 minute a.Rate(): 0.18071652714732128 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.14795817836496392-rate) > epsilon {
|
||||
t.Errorf("7 minute a.Rate(): 0.14795817836496392 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.12113791079679326-rate) > epsilon {
|
||||
t.Errorf("8 minute a.Rate(): 0.12113791079679326 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.09917933293295193-rate) > epsilon {
|
||||
t.Errorf("9 minute a.Rate(): 0.09917933293295193 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.08120116994196763-rate) > epsilon {
|
||||
t.Errorf("10 minute a.Rate(): 0.08120116994196763 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.06648189501740036-rate) > epsilon {
|
||||
t.Errorf("11 minute a.Rate(): 0.06648189501740036 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.05443077197364752-rate) > epsilon {
|
||||
t.Errorf("12 minute a.Rate(): 0.05443077197364752 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.04456414692860035-rate) > epsilon {
|
||||
t.Errorf("13 minute a.Rate(): 0.04456414692860035 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.03648603757513079-rate) > epsilon {
|
||||
t.Errorf("14 minute a.Rate(): 0.03648603757513079 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.0298722410207183831020718428-rate) > epsilon {
|
||||
t.Errorf("15 minute a.Rate(): 0.0298722410207183831020718428 != %v\n", rate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEWMA15(t *testing.T) {
|
||||
a := NewEWMA15()
|
||||
a.Update(3)
|
||||
a.Tick()
|
||||
if rate := a.Rate(); math.Abs(0.6-rate) > epsilon {
|
||||
t.Errorf("initial a.Rate(): 0.6 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.5613041910189706-rate) > epsilon {
|
||||
t.Errorf("1 minute a.Rate(): 0.5613041910189706 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.5251039914257684-rate) > epsilon {
|
||||
t.Errorf("2 minute a.Rate(): 0.5251039914257684 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.4912384518467888184678905-rate) > epsilon {
|
||||
t.Errorf("3 minute a.Rate(): 0.4912384518467888184678905 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.459557003018789-rate) > epsilon {
|
||||
t.Errorf("4 minute a.Rate(): 0.459557003018789 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.4299187863442732-rate) > epsilon {
|
||||
t.Errorf("5 minute a.Rate(): 0.4299187863442732 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.4021920276213831-rate) > epsilon {
|
||||
t.Errorf("6 minute a.Rate(): 0.4021920276213831 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.37625345116383313-rate) > epsilon {
|
||||
t.Errorf("7 minute a.Rate(): 0.37625345116383313 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.3519877317060185-rate) > epsilon {
|
||||
t.Errorf("8 minute a.Rate(): 0.3519877317060185 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.3292869816564153165641596-rate) > epsilon {
|
||||
t.Errorf("9 minute a.Rate(): 0.3292869816564153165641596 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.3080502714195546-rate) > epsilon {
|
||||
t.Errorf("10 minute a.Rate(): 0.3080502714195546 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.2881831806538789-rate) > epsilon {
|
||||
t.Errorf("11 minute a.Rate(): 0.2881831806538789 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.26959737847033216-rate) > epsilon {
|
||||
t.Errorf("12 minute a.Rate(): 0.26959737847033216 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.2522102307052083-rate) > epsilon {
|
||||
t.Errorf("13 minute a.Rate(): 0.2522102307052083 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.23594443252115815-rate) > epsilon {
|
||||
t.Errorf("14 minute a.Rate(): 0.23594443252115815 != %v\n", rate)
|
||||
}
|
||||
elapseMinute(a)
|
||||
if rate := a.Rate(); math.Abs(0.2207276647028646247028654470286553-rate) > epsilon {
|
||||
t.Errorf("15 minute a.Rate(): 0.2207276647028646247028654470286553 != %v\n", rate)
|
||||
}
|
||||
}
|
||||
|
||||
func elapseMinute(a EWMA) {
|
||||
for i := 0; i < 12; i++ {
|
||||
a.Tick()
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
package metrics
|
||||
|
||||
// Gauges hold an int64 value that can be set arbitrarily.
|
||||
type Gauge interface {
|
||||
Snapshot() Gauge
|
||||
Update(int64)
|
||||
Dec(int64)
|
||||
Inc(int64)
|
||||
Value() int64
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package metrics
|
||||
|
||||
// GaugeFloat64s hold a float64 value that can be set arbitrarily.
|
||||
type GaugeFloat64 interface {
|
||||
Snapshot() GaugeFloat64
|
||||
Update(float64)
|
||||
Value() float64
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package metrics
|
||||
|
||||
// Healthchecks hold an error value describing an arbitrary up/down status.
|
||||
type Healthcheck interface {
|
||||
Check()
|
||||
Error() error
|
||||
Healthy()
|
||||
Unhealthy(error)
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
package metrics
|
||||
|
||||
// Histograms calculate distribution statistics from a series of int64 values.
|
||||
type Histogram interface {
|
||||
Clear()
|
||||
Count() int64
|
||||
Max() int64
|
||||
Mean() float64
|
||||
Min() int64
|
||||
Percentile(float64) float64
|
||||
Percentiles([]float64) []float64
|
||||
Sample() Sample
|
||||
Snapshot() Histogram
|
||||
StdDev() float64
|
||||
Sum() int64
|
||||
Update(int64)
|
||||
Variance() float64
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// MarshalJSON returns a byte slice containing a JSON representation of all
|
||||
// the metrics in the Registry.
|
||||
func (r *StandardRegistry) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(r.GetAll())
|
||||
}
|
@ -1,285 +0,0 @@
|
||||
Memory usage
|
||||
============
|
||||
|
||||
(Highly unscientific.)
|
||||
|
||||
Command used to gather static memory usage:
|
||||
|
||||
```sh
|
||||
grep ^Vm "/proc/$(ps fax | grep [m]etrics-bench | awk '{print $1}')/status"
|
||||
```
|
||||
|
||||
Program used to gather baseline memory usage:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
func main() {
|
||||
time.Sleep(600e9)
|
||||
}
|
||||
```
|
||||
|
||||
Baseline
|
||||
--------
|
||||
|
||||
```
|
||||
VmPeak: 42604 kB
|
||||
VmSize: 42604 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 1120 kB
|
||||
VmRSS: 1120 kB
|
||||
VmData: 35460 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1020 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 36 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
Program used to gather metric memory usage (with other metrics being similar):
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"metrics"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Sprintf("foo")
|
||||
metrics.NewRegistry()
|
||||
time.Sleep(600e9)
|
||||
}
|
||||
```
|
||||
|
||||
1000 counters registered
|
||||
------------------------
|
||||
|
||||
```
|
||||
VmPeak: 44016 kB
|
||||
VmSize: 44016 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 1928 kB
|
||||
VmRSS: 1928 kB
|
||||
VmData: 36868 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1024 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 40 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
**1.412 kB virtual, TODO 0.808 kB resident per counter.**
|
||||
|
||||
100000 counters registered
|
||||
--------------------------
|
||||
|
||||
```
|
||||
VmPeak: 55024 kB
|
||||
VmSize: 55024 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 12440 kB
|
||||
VmRSS: 12440 kB
|
||||
VmData: 47876 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1024 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 64 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
**0.1242 kB virtual, 0.1132 kB resident per counter.**
|
||||
|
||||
1000 gauges registered
|
||||
----------------------
|
||||
|
||||
```
|
||||
VmPeak: 44012 kB
|
||||
VmSize: 44012 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 1928 kB
|
||||
VmRSS: 1928 kB
|
||||
VmData: 36868 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1020 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 40 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
**1.408 kB virtual, 0.808 kB resident per counter.**
|
||||
|
||||
100000 gauges registered
|
||||
------------------------
|
||||
|
||||
```
|
||||
VmPeak: 55020 kB
|
||||
VmSize: 55020 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 12432 kB
|
||||
VmRSS: 12432 kB
|
||||
VmData: 47876 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1020 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 60 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
**0.12416 kB virtual, 0.11312 resident per gauge.**
|
||||
|
||||
1000 histograms with a uniform sample size of 1028
|
||||
--------------------------------------------------
|
||||
|
||||
```
|
||||
VmPeak: 72272 kB
|
||||
VmSize: 72272 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 16204 kB
|
||||
VmRSS: 16204 kB
|
||||
VmData: 65100 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1048 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 80 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
**29.668 kB virtual, TODO 15.084 resident per histogram.**
|
||||
|
||||
10000 histograms with a uniform sample size of 1028
|
||||
---------------------------------------------------
|
||||
|
||||
```
|
||||
VmPeak: 256912 kB
|
||||
VmSize: 256912 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 146204 kB
|
||||
VmRSS: 146204 kB
|
||||
VmData: 249740 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1048 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 448 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
**21.4308 kB virtual, 14.5084 kB resident per histogram.**
|
||||
|
||||
50000 histograms with a uniform sample size of 1028
|
||||
---------------------------------------------------
|
||||
|
||||
```
|
||||
VmPeak: 908112 kB
|
||||
VmSize: 908112 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 645832 kB
|
||||
VmRSS: 645588 kB
|
||||
VmData: 900940 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1048 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 1716 kB
|
||||
VmSwap: 1544 kB
|
||||
```
|
||||
|
||||
**17.31016 kB virtual, 12.88936 kB resident per histogram.**
|
||||
|
||||
1000 histograms with an exponentially-decaying sample size of 1028 and alpha of 0.015
|
||||
-------------------------------------------------------------------------------------
|
||||
|
||||
```
|
||||
VmPeak: 62480 kB
|
||||
VmSize: 62480 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 11572 kB
|
||||
VmRSS: 11572 kB
|
||||
VmData: 55308 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1048 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 64 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
**19.876 kB virtual, 10.452 kB resident per histogram.**
|
||||
|
||||
10000 histograms with an exponentially-decaying sample size of 1028 and alpha of 0.015
|
||||
--------------------------------------------------------------------------------------
|
||||
|
||||
```
|
||||
VmPeak: 153296 kB
|
||||
VmSize: 153296 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 101176 kB
|
||||
VmRSS: 101176 kB
|
||||
VmData: 146124 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1048 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 240 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
**11.0692 kB virtual, 10.0056 kB resident per histogram.**
|
||||
|
||||
50000 histograms with an exponentially-decaying sample size of 1028 and alpha of 0.015
|
||||
--------------------------------------------------------------------------------------
|
||||
|
||||
```
|
||||
VmPeak: 557264 kB
|
||||
VmSize: 557264 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 501056 kB
|
||||
VmRSS: 501056 kB
|
||||
VmData: 550092 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1048 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 1032 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
**10.2932 kB virtual, 9.99872 kB resident per histogram.**
|
||||
|
||||
1000 meters
|
||||
-----------
|
||||
|
||||
```
|
||||
VmPeak: 74504 kB
|
||||
VmSize: 74504 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 24124 kB
|
||||
VmRSS: 24124 kB
|
||||
VmData: 67340 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1040 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 92 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
**31.9 kB virtual, 23.004 kB resident per meter.**
|
||||
|
||||
10000 meters
|
||||
------------
|
||||
|
||||
```
|
||||
VmPeak: 278920 kB
|
||||
VmSize: 278920 kB
|
||||
VmLck: 0 kB
|
||||
VmHWM: 227300 kB
|
||||
VmRSS: 227300 kB
|
||||
VmData: 271756 kB
|
||||
VmStk: 136 kB
|
||||
VmExe: 1040 kB
|
||||
VmLib: 1848 kB
|
||||
VmPTE: 488 kB
|
||||
VmSwap: 0 kB
|
||||
```
|
||||
|
||||
**23.6316 kB virtual, 22.618 kB resident per meter.**
|
241
metrics/meter.go
241
metrics/meter.go
@ -1,241 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ledgerwatch/erigon/common/debug"
|
||||
)
|
||||
|
||||
// Meters count events to produce exponentially-weighted moving average rates
|
||||
// at one-, five-, and fifteen-minutes and a mean rate.
|
||||
type Meter interface {
|
||||
Count() int64
|
||||
Mark(int64)
|
||||
Rate1() float64
|
||||
Rate5() float64
|
||||
Rate15() float64
|
||||
RateMean() float64
|
||||
Snapshot() Meter
|
||||
Stop()
|
||||
}
|
||||
|
||||
// NewMeterForced constructs a new StandardMeter and launches a goroutine no matter
|
||||
// the global switch is enabled or not.
|
||||
// Be sure to call Stop() once the meter is of no use to allow for garbage collection.
|
||||
func NewMeterForced() Meter {
|
||||
m := newStandardMeter()
|
||||
arbiter.mu.Lock()
|
||||
defer arbiter.mu.Unlock()
|
||||
arbiter.meters[m] = struct{}{}
|
||||
if !arbiter.started {
|
||||
arbiter.started = true
|
||||
go arbiter.tick()
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// MeterSnapshot is a read-only copy of another Meter.
|
||||
type MeterSnapshot struct {
|
||||
// WARNING: The `temp` field is accessed atomically.
|
||||
// On 32 bit platforms, only 64-bit aligned fields can be atomic. The struct is
|
||||
// guaranteed to be so aligned, so take advantage of that. For more information,
|
||||
// see https://golang.org/pkg/sync/atomic/#pkg-note-BUG.
|
||||
temp int64
|
||||
count int64
|
||||
rate1, rate5, rate15, rateMean float64
|
||||
}
|
||||
|
||||
// Count returns the count of events at the time the snapshot was taken.
|
||||
func (m *MeterSnapshot) Count() int64 { return m.count }
|
||||
|
||||
// Mark panics.
|
||||
func (*MeterSnapshot) Mark(n int64) {
|
||||
panic("Mark called on a MeterSnapshot")
|
||||
}
|
||||
|
||||
// Rate1 returns the one-minute moving average rate of events per second at the
|
||||
// time the snapshot was taken.
|
||||
func (m *MeterSnapshot) Rate1() float64 { return m.rate1 }
|
||||
|
||||
// Rate5 returns the five-minute moving average rate of events per second at
|
||||
// the time the snapshot was taken.
|
||||
func (m *MeterSnapshot) Rate5() float64 { return m.rate5 }
|
||||
|
||||
// Rate15 returns the fifteen-minute moving average rate of events per second
|
||||
// at the time the snapshot was taken.
|
||||
func (m *MeterSnapshot) Rate15() float64 { return m.rate15 }
|
||||
|
||||
// RateMean returns the meter's mean rate of events per second at the time the
|
||||
// snapshot was taken.
|
||||
func (m *MeterSnapshot) RateMean() float64 { return m.rateMean }
|
||||
|
||||
// Snapshot returns the snapshot.
|
||||
func (m *MeterSnapshot) Snapshot() Meter { return m }
|
||||
|
||||
// Stop is a no-op.
|
||||
func (m *MeterSnapshot) Stop() {}
|
||||
|
||||
// NilMeter is a no-op Meter.
|
||||
type NilMeter struct{}
|
||||
|
||||
// Count is a no-op.
|
||||
func (NilMeter) Count() int64 { return 0 }
|
||||
|
||||
// Mark is a no-op.
|
||||
func (NilMeter) Mark(n int64) {}
|
||||
|
||||
// Rate1 is a no-op.
|
||||
func (NilMeter) Rate1() float64 { return 0.0 }
|
||||
|
||||
// Rate5 is a no-op.
|
||||
func (NilMeter) Rate5() float64 { return 0.0 }
|
||||
|
||||
// Rate15 is a no-op.
|
||||
func (NilMeter) Rate15() float64 { return 0.0 }
|
||||
|
||||
// RateMean is a no-op.
|
||||
func (NilMeter) RateMean() float64 { return 0.0 }
|
||||
|
||||
// Snapshot is a no-op.
|
||||
func (NilMeter) Snapshot() Meter { return NilMeter{} }
|
||||
|
||||
// Stop is a no-op.
|
||||
func (NilMeter) Stop() {}
|
||||
|
||||
// StandardMeter is the standard implementation of a Meter.
|
||||
type StandardMeter struct {
|
||||
lock sync.RWMutex
|
||||
snapshot *MeterSnapshot
|
||||
a1, a5, a15 EWMA
|
||||
startTime time.Time
|
||||
stopped uint32
|
||||
}
|
||||
|
||||
func newStandardMeter() *StandardMeter {
|
||||
return &StandardMeter{
|
||||
snapshot: &MeterSnapshot{},
|
||||
a1: NewEWMA1(),
|
||||
a5: NewEWMA5(),
|
||||
a15: NewEWMA15(),
|
||||
startTime: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// Stop stops the meter, Mark() will be a no-op if you use it after being stopped.
|
||||
func (m *StandardMeter) Stop() {
|
||||
stopped := atomic.SwapUint32(&m.stopped, 1)
|
||||
if stopped != 1 {
|
||||
arbiter.mu.Lock()
|
||||
delete(arbiter.meters, m)
|
||||
arbiter.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Count returns the number of events recorded.
|
||||
// It updates the meter to be as accurate as possible
|
||||
func (m *StandardMeter) Count() int64 {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
m.updateMeter()
|
||||
return m.snapshot.count
|
||||
}
|
||||
|
||||
// Mark records the occurrence of n events.
|
||||
func (m *StandardMeter) Mark(n int64) {
|
||||
m.lock.Lock()
|
||||
m.snapshot.temp = n
|
||||
m.lock.Unlock()
|
||||
}
|
||||
|
||||
// Rate1 returns the one-minute moving average rate of events per second.
|
||||
func (m *StandardMeter) Rate1() float64 {
|
||||
m.lock.RLock()
|
||||
defer m.lock.RUnlock()
|
||||
return m.snapshot.rate1
|
||||
}
|
||||
|
||||
// Rate5 returns the five-minute moving average rate of events per second.
|
||||
func (m *StandardMeter) Rate5() float64 {
|
||||
m.lock.RLock()
|
||||
defer m.lock.RUnlock()
|
||||
return m.snapshot.rate5
|
||||
}
|
||||
|
||||
// Rate15 returns the fifteen-minute moving average rate of events per second.
|
||||
func (m *StandardMeter) Rate15() float64 {
|
||||
m.lock.RLock()
|
||||
defer m.lock.RUnlock()
|
||||
return m.snapshot.rate15
|
||||
}
|
||||
|
||||
// RateMean returns the meter's mean rate of events per second.
|
||||
func (m *StandardMeter) RateMean() float64 {
|
||||
m.lock.RLock()
|
||||
defer m.lock.RUnlock()
|
||||
return m.snapshot.rateMean
|
||||
}
|
||||
|
||||
// Snapshot returns a read-only copy of the meter.
|
||||
func (m *StandardMeter) Snapshot() Meter {
|
||||
m.lock.RLock()
|
||||
snapshot := *m.snapshot
|
||||
m.lock.RUnlock()
|
||||
return &snapshot
|
||||
}
|
||||
|
||||
func (m *StandardMeter) updateSnapshot() {
|
||||
// should run with write lock held on m.lock
|
||||
snapshot := m.snapshot
|
||||
snapshot.rate1 = m.a1.Rate()
|
||||
snapshot.rate5 = m.a5.Rate()
|
||||
snapshot.rate15 = m.a15.Rate()
|
||||
snapshot.rateMean = float64(snapshot.count) / time.Since(m.startTime).Seconds()
|
||||
}
|
||||
|
||||
func (m *StandardMeter) updateMeter() {
|
||||
// should only run with write lock held on m.lock
|
||||
n := atomic.SwapInt64(&m.snapshot.temp, 0)
|
||||
m.snapshot.count += n
|
||||
m.a1.Update(n)
|
||||
m.a5.Update(n)
|
||||
m.a15.Update(n)
|
||||
}
|
||||
|
||||
func (m *StandardMeter) tick() {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
m.updateMeter()
|
||||
m.a1.Tick()
|
||||
m.a5.Tick()
|
||||
m.a15.Tick()
|
||||
m.updateSnapshot()
|
||||
}
|
||||
|
||||
// meterArbiter ticks meters every 5s from a single goroutine.
|
||||
// meters are references in a set for future stopping.
|
||||
type meterArbiter struct {
|
||||
mu sync.RWMutex
|
||||
started bool
|
||||
meters map[*StandardMeter]struct{}
|
||||
ticker *time.Ticker
|
||||
}
|
||||
|
||||
var arbiter = meterArbiter{ticker: time.NewTicker(5 * time.Second), meters: make(map[*StandardMeter]struct{})}
|
||||
|
||||
// Ticks meters on the scheduled interval
|
||||
func (ma *meterArbiter) tick() {
|
||||
defer debug.LogPanic()
|
||||
for range ma.ticker.C {
|
||||
ma.tickMeters()
|
||||
}
|
||||
}
|
||||
|
||||
func (ma *meterArbiter) tickMeters() {
|
||||
ma.mu.RLock()
|
||||
defer ma.mu.RUnlock()
|
||||
for meter := range ma.meters {
|
||||
meter.tick()
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestMeterDecay(t *testing.T) {
|
||||
ma := meterArbiter{
|
||||
ticker: time.NewTicker(time.Millisecond),
|
||||
meters: make(map[*StandardMeter]struct{}),
|
||||
}
|
||||
defer ma.ticker.Stop()
|
||||
m := newStandardMeter()
|
||||
ma.meters[m] = struct{}{}
|
||||
m.Mark(1)
|
||||
ma.tickMeters()
|
||||
rateMean := m.RateMean()
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
ma.tickMeters()
|
||||
if m.RateMean() >= rateMean {
|
||||
t.Error("m.RateMean() didn't decrease")
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
// Go port of Coda Hale's Metrics library
|
||||
//
|
||||
// <https://github.com/rcrowley/go-metrics>
|
||||
//
|
||||
// Coda Hale's original work: <https://github.com/codahale/metrics>
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"runtime/metrics"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// callbacks - storing list of callbacks as type []func()
|
||||
// use metrics.AddCallback to add your function to metrics collection loop (to avoid multiple goroutines collecting metrics)
|
||||
var callbacks atomic.Value
|
||||
|
||||
func init() {
|
||||
metrics.All()
|
||||
callbacks.Store([]func(){})
|
||||
}
|
||||
|
||||
// Calling Load method
|
@ -31,9 +31,6 @@ type Registry interface {
|
||||
// Get the metric by the given name or nil if none is registered.
|
||||
Get(string) interface{}
|
||||
|
||||
// GetAll metrics in the Registry.
|
||||
GetAll() map[string]map[string]interface{}
|
||||
|
||||
// Gets an existing metric or registers the given one.
|
||||
// The interface can be the metric to register if not found in registry,
|
||||
// or a function returning the metric for lazy instantiation.
|
||||
@ -42,9 +39,6 @@ type Registry interface {
|
||||
// Register the given metric under the given name.
|
||||
Register(string, interface{}) error
|
||||
|
||||
// Run all registered healthchecks.
|
||||
RunHealthchecks()
|
||||
|
||||
// Unregister the metric with the given name.
|
||||
Unregister(string)
|
||||
|
||||
@ -103,78 +97,6 @@ func (r *StandardRegistry) Register(name string, i interface{}) error {
|
||||
return r.register(name, i)
|
||||
}
|
||||
|
||||
// Run all registered healthchecks.
|
||||
func (r *StandardRegistry) RunHealthchecks() {
|
||||
r.mutex.Lock()
|
||||
defer r.mutex.Unlock()
|
||||
for _, i := range r.metrics {
|
||||
if h, ok := i.(Healthcheck); ok {
|
||||
h.Check()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GetAll metrics in the Registry
|
||||
func (r *StandardRegistry) GetAll() map[string]map[string]interface{} {
|
||||
data := make(map[string]map[string]interface{})
|
||||
r.Each(func(name string, i interface{}) {
|
||||
values := make(map[string]interface{})
|
||||
switch metric := i.(type) {
|
||||
case Counter:
|
||||
values["count"] = metric.Count()
|
||||
case Gauge:
|
||||
values["value"] = metric.Value()
|
||||
case GaugeFloat64:
|
||||
values["value"] = metric.Value()
|
||||
case Healthcheck:
|
||||
values["error"] = nil
|
||||
metric.Check()
|
||||
if err := metric.Error(); nil != err {
|
||||
values["error"] = metric.Error().Error()
|
||||
}
|
||||
case Histogram:
|
||||
h := metric.Snapshot()
|
||||
ps := h.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
|
||||
values["count"] = h.Count()
|
||||
values["min"] = h.Min()
|
||||
values["max"] = h.Max()
|
||||
values["mean"] = h.Mean()
|
||||
values["stddev"] = h.StdDev()
|
||||
values["median"] = ps[0]
|
||||
values["75%"] = ps[1]
|
||||
values["95%"] = ps[2]
|
||||
values["99%"] = ps[3]
|
||||
values["99.9%"] = ps[4]
|
||||
case Meter:
|
||||
m := metric.Snapshot()
|
||||
values["count"] = m.Count()
|
||||
values["1m.rate"] = m.Rate1()
|
||||
values["5m.rate"] = m.Rate5()
|
||||
values["15m.rate"] = m.Rate15()
|
||||
values["mean.rate"] = m.RateMean()
|
||||
case Timer:
|
||||
t := metric.Snapshot()
|
||||
ps := t.Percentiles([]float64{0.5, 0.75, 0.95, 0.99, 0.999})
|
||||
values["count"] = t.Count()
|
||||
values["min"] = t.Min()
|
||||
values["max"] = t.Max()
|
||||
values["mean"] = t.Mean()
|
||||
values["stddev"] = t.StdDev()
|
||||
values["median"] = ps[0]
|
||||
values["75%"] = ps[1]
|
||||
values["95%"] = ps[2]
|
||||
values["99%"] = ps[3]
|
||||
values["99.9%"] = ps[4]
|
||||
values["1m.rate"] = t.Rate1()
|
||||
values["5m.rate"] = t.Rate5()
|
||||
values["15m.rate"] = t.Rate15()
|
||||
values["mean.rate"] = t.RateMean()
|
||||
}
|
||||
data[name] = values
|
||||
})
|
||||
return data
|
||||
}
|
||||
|
||||
// Unregister the metric with the given name.
|
||||
func (r *StandardRegistry) Unregister(name string) {
|
||||
r.mutex.Lock()
|
||||
@ -198,7 +120,7 @@ func (r *StandardRegistry) register(name string, i interface{}) error {
|
||||
return DuplicateMetric(name)
|
||||
}
|
||||
switch i.(type) {
|
||||
case Counter, Gauge, GaugeFloat64, Healthcheck, Histogram, Meter, Timer, ResettingTimer, *metrics2.Counter, *metrics2.Gauge, *metrics2.FloatCounter, *metrics2.Histogram, *metrics2.Summary:
|
||||
case *metrics2.Counter, *metrics2.Gauge, *metrics2.FloatCounter, *metrics2.Histogram, *metrics2.Summary:
|
||||
r.metrics[name] = i
|
||||
default:
|
||||
log.Info("Type not registered(metrics won't show): ", reflect.TypeOf(i))
|
||||
|
@ -1,16 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// ResettingTimer is used for storing aggregated values for timers, which are reset on every flush interval.
|
||||
type ResettingTimer interface {
|
||||
Values() []int64
|
||||
Snapshot() ResettingTimer
|
||||
Percentiles([]float64) []int64
|
||||
Mean() float64
|
||||
Time(func())
|
||||
Update(time.Duration)
|
||||
UpdateSince(time.Time)
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ledgerwatch/erigon-lib/common/dbg"
|
||||
)
|
||||
|
||||
func TestRuntimeMemStatsBlocking(t *testing.T) {
|
||||
if g := runtime.GOMAXPROCS(0); g < 2 {
|
||||
t.Skipf("skipping TestRuntimeMemStatsBlocking with GOMAXPROCS=%d\n", g)
|
||||
}
|
||||
ch := make(chan int)
|
||||
go testRuntimeMemStatsBlocking(ch)
|
||||
var memStats runtime.MemStats
|
||||
t0 := time.Now()
|
||||
dbg.ReadMemStats(&memStats)
|
||||
t1 := time.Now()
|
||||
t.Log("i++ during runtime.ReadMemStats:", <-ch)
|
||||
go testRuntimeMemStatsBlocking(ch)
|
||||
d := t1.Sub(t0)
|
||||
t.Log(d)
|
||||
time.Sleep(d)
|
||||
t.Log("i++ during time.Sleep:", <-ch)
|
||||
}
|
||||
|
||||
func testRuntimeMemStatsBlocking(ch chan int) {
|
||||
i := 0
|
||||
for {
|
||||
select {
|
||||
case ch <- i:
|
||||
return
|
||||
default:
|
||||
i++
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package metrics
|
||||
|
||||
// Samples maintain a statistically-significant selection of values from
|
||||
// a stream.
|
||||
type Sample interface {
|
||||
Clear()
|
||||
Count() int64
|
||||
Max() int64
|
||||
Mean() float64
|
||||
Min() int64
|
||||
Percentile(float64) float64
|
||||
Percentiles([]float64) []float64
|
||||
Size() int
|
||||
Snapshot() Sample
|
||||
StdDev() float64
|
||||
Sum() int64
|
||||
Update(int64)
|
||||
Values() []int64
|
||||
Variance() float64
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Timers capture the duration and rate of events.
|
||||
type Timer interface {
|
||||
Count() int64
|
||||
Max() int64
|
||||
Mean() float64
|
||||
Min() int64
|
||||
Percentile(float64) float64
|
||||
Percentiles([]float64) []float64
|
||||
Rate1() float64
|
||||
Rate5() float64
|
||||
Rate15() float64
|
||||
RateMean() float64
|
||||
Snapshot() Timer
|
||||
StdDev() float64
|
||||
Stop()
|
||||
Sum() int64
|
||||
Time(func())
|
||||
Update(time.Duration)
|
||||
UpdateSince(time.Time)
|
||||
Variance() float64
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# check there are no formatting issues
|
||||
GOFMT_LINES=`gofmt -l . | wc -l | xargs`
|
||||
test $GOFMT_LINES -eq 0 || echo "gofmt needs to be run, ${GOFMT_LINES} files have issues"
|
||||
|
||||
# run the tests for the root package
|
||||
go test -race .
|
@ -48,7 +48,7 @@ type Server struct {
|
||||
methodAllowList AllowList
|
||||
idgen func() ID
|
||||
run int32
|
||||
codecs mapset.Set
|
||||
codecs mapset.Set // mapset.Set[ServerCodec] requires go 1.20
|
||||
|
||||
batchConcurrency uint
|
||||
disableStreaming bool
|
||||
|
@ -27,7 +27,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set"
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/ledgerwatch/log/v3"
|
||||
)
|
||||
@ -72,7 +72,7 @@ func (s *Server) WebsocketHandler(allowedOrigins []string, jwtSecret []byte, com
|
||||
// websocket upgrade process. When a '*' is specified as an allowed origins all
|
||||
// connections are accepted.
|
||||
func wsHandshakeValidator(allowedOrigins []string, logger log.Logger) func(*http.Request) bool {
|
||||
origins := mapset.NewSet()
|
||||
origins := mapset.NewSet[string]()
|
||||
allowAllOrigins := false
|
||||
|
||||
for _, origin := range allowedOrigins {
|
||||
@ -125,10 +125,10 @@ func (e wsHandshakeError) Error() string {
|
||||
return s
|
||||
}
|
||||
|
||||
func originIsAllowed(allowedOrigins mapset.Set, browserOrigin string, logger log.Logger) bool {
|
||||
func originIsAllowed(allowedOrigins mapset.Set[string], browserOrigin string, logger log.Logger) bool {
|
||||
it := allowedOrigins.Iterator()
|
||||
for origin := range it.C {
|
||||
if ruleAllowsOrigin(origin.(string), browserOrigin, logger) {
|
||||
if ruleAllowsOrigin(origin, browserOrigin, logger) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ import (
|
||||
func TestState(t *testing.T) {
|
||||
defer log.Root().SetHandler(log.Root().GetHandler())
|
||||
log.Root().SetHandler(log.LvlFilterHandler(log.LvlError, log.StderrHandler))
|
||||
if runtime.GOOS == "windows" {
|
||||
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
|
||||
t.Skip("fix me on win please") // it's too slow on win, need generally improve speed of this tests
|
||||
}
|
||||
//t.Parallel()
|
||||
|
Loading…
Reference in New Issue
Block a user