mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-25 20:37:53 +08:00
Vendor github.com/codahale/metrics
This commit is contained in:
parent
df70fe4ac7
commit
a8f0d3d411
8
Godeps/Godeps.json
generated
8
Godeps/Godeps.json
generated
@ -57,6 +57,14 @@
|
||||
"ImportPath": "github.com/chuckpreslar/inflect",
|
||||
"Rev": "423e3ac59c611e2d549527ab8c15fb99335d30ba"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/codahale/hdrhistogram",
|
||||
"Rev": "5fd85ec0b4e2dd5d4158d257d943f2e586d86b62"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/codahale/metrics",
|
||||
"Rev": "7d3beb1b480077e77c08a6f6c65ea969f6e91420"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/coreos/go-semver/semver",
|
||||
"Rev": "568e959cd89871e61434c1143528d9162da89ef2"
|
||||
|
||||
9
Godeps/_workspace/src/github.com/codahale/hdrhistogram/.travis.yml
generated
vendored
Normal file
9
Godeps/_workspace/src/github.com/codahale/hdrhistogram/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.3.3
|
||||
notifications:
|
||||
# See http://about.travis-ci.org/docs/user/build-configuration/ to learn more
|
||||
# about configuring notification recipients and more.
|
||||
email:
|
||||
recipients:
|
||||
- coda.hale@gmail.com
|
||||
21
Godeps/_workspace/src/github.com/codahale/hdrhistogram/LICENSE
generated
vendored
Normal file
21
Godeps/_workspace/src/github.com/codahale/hdrhistogram/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Coda Hale
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
15
Godeps/_workspace/src/github.com/codahale/hdrhistogram/README.md
generated
vendored
Normal file
15
Godeps/_workspace/src/github.com/codahale/hdrhistogram/README.md
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
hdrhistogram
|
||||
============
|
||||
|
||||
[](https://travis-ci.org/codahale/hdrhistogram)
|
||||
|
||||
A pure Go implementation of the [HDR Histogram](https://github.com/HdrHistogram/HdrHistogram).
|
||||
|
||||
> A Histogram that supports recording and analyzing sampled data value counts
|
||||
> across a configurable integer value range with configurable value precision
|
||||
> within the range. Value precision is expressed as the number of significant
|
||||
> digits in the value recording, and provides control over value quantization
|
||||
> behavior across the value range and the subsequent value resolution at any
|
||||
> given level.
|
||||
|
||||
For documentation, check [godoc](http://godoc.org/github.com/codahale/hdrhistogram).
|
||||
513
Godeps/_workspace/src/github.com/codahale/hdrhistogram/hdr.go
generated
vendored
Normal file
513
Godeps/_workspace/src/github.com/codahale/hdrhistogram/hdr.go
generated
vendored
Normal file
@ -0,0 +1,513 @@
|
||||
// Package hdrhistogram provides an implementation of Gil Tene's HDR Histogram
|
||||
// data structure. The HDR Histogram allows for fast and accurate analysis of
|
||||
// the extreme ranges of data with non-normal distributions, like latency.
|
||||
package hdrhistogram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// A Bracket is a part of a cumulative distribution.
|
||||
type Bracket struct {
|
||||
Quantile float64
|
||||
Count, ValueAt int64
|
||||
}
|
||||
|
||||
// A Snapshot is an exported view of a Histogram, useful for serializing them.
|
||||
// A Histogram can be constructed from it by passing it to Import.
|
||||
type Snapshot struct {
|
||||
LowestTrackableValue int64
|
||||
HighestTrackableValue int64
|
||||
SignificantFigures int64
|
||||
Counts []int64
|
||||
}
|
||||
|
||||
// A Histogram is a lossy data structure used to record the distribution of
|
||||
// non-normally distributed data (like latency) with a high degree of accuracy
|
||||
// and a bounded degree of precision.
|
||||
type Histogram struct {
|
||||
lowestTrackableValue int64
|
||||
highestTrackableValue int64
|
||||
unitMagnitude int64
|
||||
significantFigures int64
|
||||
subBucketHalfCountMagnitude int32
|
||||
subBucketHalfCount int32
|
||||
subBucketMask int64
|
||||
subBucketCount int32
|
||||
bucketCount int32
|
||||
countsLen int32
|
||||
totalCount int64
|
||||
counts []int64
|
||||
}
|
||||
|
||||
// New returns a new Histogram instance capable of tracking values in the given
|
||||
// range and with the given amount of precision.
|
||||
func New(minValue, maxValue int64, sigfigs int) *Histogram {
|
||||
if sigfigs < 1 || 5 < sigfigs {
|
||||
panic(fmt.Errorf("sigfigs must be [1,5] (was %d)", sigfigs))
|
||||
}
|
||||
|
||||
largestValueWithSingleUnitResolution := 2 * math.Pow10(sigfigs)
|
||||
subBucketCountMagnitude := int32(math.Ceil(math.Log2(float64(largestValueWithSingleUnitResolution))))
|
||||
|
||||
subBucketHalfCountMagnitude := subBucketCountMagnitude
|
||||
if subBucketHalfCountMagnitude < 1 {
|
||||
subBucketHalfCountMagnitude = 1
|
||||
}
|
||||
subBucketHalfCountMagnitude--
|
||||
|
||||
unitMagnitude := int32(math.Floor(math.Log2(float64(minValue))))
|
||||
if unitMagnitude < 0 {
|
||||
unitMagnitude = 0
|
||||
}
|
||||
|
||||
subBucketCount := int32(math.Pow(2, float64(subBucketHalfCountMagnitude)+1))
|
||||
|
||||
subBucketHalfCount := subBucketCount / 2
|
||||
subBucketMask := int64(subBucketCount-1) << uint(unitMagnitude)
|
||||
|
||||
// determine exponent range needed to support the trackable value with no
|
||||
// overflow:
|
||||
smallestUntrackableValue := int64(subBucketCount) << uint(unitMagnitude)
|
||||
bucketsNeeded := int32(1)
|
||||
for smallestUntrackableValue < maxValue {
|
||||
smallestUntrackableValue <<= 1
|
||||
bucketsNeeded++
|
||||
}
|
||||
|
||||
bucketCount := bucketsNeeded
|
||||
countsLen := (bucketCount + 1) * (subBucketCount / 2)
|
||||
|
||||
return &Histogram{
|
||||
lowestTrackableValue: minValue,
|
||||
highestTrackableValue: maxValue,
|
||||
unitMagnitude: int64(unitMagnitude),
|
||||
significantFigures: int64(sigfigs),
|
||||
subBucketHalfCountMagnitude: subBucketHalfCountMagnitude,
|
||||
subBucketHalfCount: subBucketHalfCount,
|
||||
subBucketMask: subBucketMask,
|
||||
subBucketCount: subBucketCount,
|
||||
bucketCount: bucketCount,
|
||||
countsLen: countsLen,
|
||||
totalCount: 0,
|
||||
counts: make([]int64, countsLen),
|
||||
}
|
||||
}
|
||||
|
||||
// ByteSize returns an estimate of the amount of memory allocated to the
|
||||
// histogram in bytes.
|
||||
//
|
||||
// N.B.: This does not take into account the overhead for slices, which are
|
||||
// small, constant, and specific to the compiler version.
|
||||
func (h *Histogram) ByteSize() int {
|
||||
return 6*8 + 5*4 + len(h.counts)*8
|
||||
}
|
||||
|
||||
// Merge merges the data stored in the given histogram with the receiver,
|
||||
// returning the number of recorded values which had to be dropped.
|
||||
func (h *Histogram) Merge(from *Histogram) (dropped int64) {
|
||||
i := from.rIterator()
|
||||
for i.next() {
|
||||
v := i.valueFromIdx
|
||||
c := i.countAtIdx
|
||||
|
||||
if h.RecordValues(v, c) != nil {
|
||||
dropped += c
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// TotalCount returns total number of values recorded.
|
||||
func (h *Histogram) TotalCount() int64 {
|
||||
return h.totalCount
|
||||
}
|
||||
|
||||
// Max returns the approximate maximum recorded value.
|
||||
func (h *Histogram) Max() int64 {
|
||||
var max int64
|
||||
i := h.iterator()
|
||||
for i.next() {
|
||||
if i.countAtIdx != 0 {
|
||||
max = i.highestEquivalentValue
|
||||
}
|
||||
}
|
||||
return h.lowestEquivalentValue(max)
|
||||
}
|
||||
|
||||
// Min returns the approximate minimum recorded value.
|
||||
func (h *Histogram) Min() int64 {
|
||||
var min int64
|
||||
i := h.iterator()
|
||||
for i.next() {
|
||||
if i.countAtIdx != 0 && min == 0 {
|
||||
min = i.highestEquivalentValue
|
||||
break
|
||||
}
|
||||
}
|
||||
return h.lowestEquivalentValue(min)
|
||||
}
|
||||
|
||||
// Mean returns the approximate arithmetic mean of the recorded values.
|
||||
func (h *Histogram) Mean() float64 {
|
||||
var total int64
|
||||
i := h.iterator()
|
||||
for i.next() {
|
||||
if i.countAtIdx != 0 {
|
||||
total += i.countAtIdx * h.medianEquivalentValue(i.valueFromIdx)
|
||||
}
|
||||
}
|
||||
return float64(total) / float64(h.totalCount)
|
||||
}
|
||||
|
||||
// StdDev returns the approximate standard deviation of the recorded values.
|
||||
func (h *Histogram) StdDev() float64 {
|
||||
mean := h.Mean()
|
||||
geometricDevTotal := 0.0
|
||||
|
||||
i := h.iterator()
|
||||
for i.next() {
|
||||
if i.countAtIdx != 0 {
|
||||
dev := float64(h.medianEquivalentValue(i.valueFromIdx)) - mean
|
||||
geometricDevTotal += (dev * dev) * float64(i.countAtIdx)
|
||||
}
|
||||
}
|
||||
|
||||
return math.Sqrt(geometricDevTotal / float64(h.totalCount))
|
||||
}
|
||||
|
||||
// Reset deletes all recorded values and restores the histogram to its original
|
||||
// state.
|
||||
func (h *Histogram) Reset() {
|
||||
h.totalCount = 0
|
||||
for i := range h.counts {
|
||||
h.counts[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// RecordValue records the given value, returning an error if the value is out
|
||||
// of range.
|
||||
func (h *Histogram) RecordValue(v int64) error {
|
||||
return h.RecordValues(v, 1)
|
||||
}
|
||||
|
||||
// RecordCorrectedValue records the given value, correcting for stalls in the
|
||||
// recording process. This only works for processes which are recording values
|
||||
// at an expected interval (e.g., doing jitter analysis). Processes which are
|
||||
// recording ad-hoc values (e.g., latency for incoming requests) can't take
|
||||
// advantage of this.
|
||||
func (h *Histogram) RecordCorrectedValue(v, expectedInterval int64) error {
|
||||
if err := h.RecordValue(v); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if expectedInterval <= 0 || v <= expectedInterval {
|
||||
return nil
|
||||
}
|
||||
|
||||
missingValue := v - expectedInterval
|
||||
for missingValue >= expectedInterval {
|
||||
if err := h.RecordValue(missingValue); err != nil {
|
||||
return err
|
||||
}
|
||||
missingValue -= expectedInterval
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RecordValues records n occurrences of the given value, returning an error if
|
||||
// the value is out of range.
|
||||
func (h *Histogram) RecordValues(v, n int64) error {
|
||||
idx := h.countsIndexFor(v)
|
||||
if idx < 0 || int(h.countsLen) <= idx {
|
||||
return fmt.Errorf("value %d is too large to be recorded", v)
|
||||
}
|
||||
h.counts[idx] += n
|
||||
h.totalCount += n
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValueAtQuantile returns the recorded value at the given quantile (0..100).
|
||||
func (h *Histogram) ValueAtQuantile(q float64) int64 {
|
||||
if q > 100 {
|
||||
q = 100
|
||||
}
|
||||
|
||||
total := int64(0)
|
||||
countAtPercentile := int64(((q / 100) * float64(h.totalCount)) + 0.5)
|
||||
|
||||
i := h.iterator()
|
||||
for i.next() {
|
||||
total += i.countAtIdx
|
||||
if total >= countAtPercentile {
|
||||
return h.highestEquivalentValue(i.valueFromIdx)
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// CumulativeDistribution returns an ordered list of brackets of the
|
||||
// distribution of recorded values.
|
||||
func (h *Histogram) CumulativeDistribution() []Bracket {
|
||||
var result []Bracket
|
||||
|
||||
i := h.pIterator(1)
|
||||
for i.next() {
|
||||
result = append(result, Bracket{
|
||||
Quantile: i.percentile,
|
||||
Count: i.countToIdx,
|
||||
ValueAt: i.highestEquivalentValue,
|
||||
})
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Equals returns true if the two Histograms are equivalent, false if not.
|
||||
func (h *Histogram) Equals(other *Histogram) bool {
|
||||
switch {
|
||||
case
|
||||
h.lowestTrackableValue != other.lowestTrackableValue,
|
||||
h.highestTrackableValue != other.highestTrackableValue,
|
||||
h.unitMagnitude != other.unitMagnitude,
|
||||
h.significantFigures != other.significantFigures,
|
||||
h.subBucketHalfCountMagnitude != other.subBucketHalfCountMagnitude,
|
||||
h.subBucketHalfCount != other.subBucketHalfCount,
|
||||
h.subBucketMask != other.subBucketMask,
|
||||
h.subBucketCount != other.subBucketCount,
|
||||
h.bucketCount != other.bucketCount,
|
||||
h.countsLen != other.countsLen,
|
||||
h.totalCount != other.totalCount:
|
||||
return false
|
||||
default:
|
||||
for i, c := range h.counts {
|
||||
if c != other.counts[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Export returns a snapshot view of the Histogram. This can be later passed to
|
||||
// Import to construct a new Histogram with the same state.
|
||||
func (h *Histogram) Export() *Snapshot {
|
||||
return &Snapshot{
|
||||
LowestTrackableValue: h.lowestTrackableValue,
|
||||
HighestTrackableValue: h.highestTrackableValue,
|
||||
SignificantFigures: h.significantFigures,
|
||||
Counts: h.counts,
|
||||
}
|
||||
}
|
||||
|
||||
// Import returns a new Histogram populated from the Snapshot data.
|
||||
func Import(s *Snapshot) *Histogram {
|
||||
h := New(s.LowestTrackableValue, s.HighestTrackableValue, int(s.SignificantFigures))
|
||||
h.counts = s.Counts
|
||||
totalCount := int64(0)
|
||||
for i := int32(0); i < h.countsLen; i++ {
|
||||
countAtIndex := h.counts[i]
|
||||
if countAtIndex > 0 {
|
||||
totalCount += countAtIndex
|
||||
}
|
||||
}
|
||||
h.totalCount = totalCount
|
||||
return h
|
||||
}
|
||||
|
||||
func (h *Histogram) iterator() *iterator {
|
||||
return &iterator{
|
||||
h: h,
|
||||
subBucketIdx: -1,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Histogram) rIterator() *rIterator {
|
||||
return &rIterator{
|
||||
iterator: iterator{
|
||||
h: h,
|
||||
subBucketIdx: -1,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Histogram) pIterator(ticksPerHalfDistance int32) *pIterator {
|
||||
return &pIterator{
|
||||
iterator: iterator{
|
||||
h: h,
|
||||
subBucketIdx: -1,
|
||||
},
|
||||
ticksPerHalfDistance: ticksPerHalfDistance,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Histogram) sizeOfEquivalentValueRange(v int64) int64 {
|
||||
bucketIdx := h.getBucketIndex(v)
|
||||
subBucketIdx := h.getSubBucketIdx(v, bucketIdx)
|
||||
adjustedBucket := bucketIdx
|
||||
if subBucketIdx >= h.subBucketCount {
|
||||
adjustedBucket++
|
||||
}
|
||||
return int64(1) << uint(h.unitMagnitude+int64(adjustedBucket))
|
||||
}
|
||||
|
||||
func (h *Histogram) valueFromIndex(bucketIdx, subBucketIdx int32) int64 {
|
||||
return int64(subBucketIdx) << uint(int64(bucketIdx)+h.unitMagnitude)
|
||||
}
|
||||
|
||||
func (h *Histogram) lowestEquivalentValue(v int64) int64 {
|
||||
bucketIdx := h.getBucketIndex(v)
|
||||
subBucketIdx := h.getSubBucketIdx(v, bucketIdx)
|
||||
return h.valueFromIndex(bucketIdx, subBucketIdx)
|
||||
}
|
||||
|
||||
func (h *Histogram) nextNonEquivalentValue(v int64) int64 {
|
||||
return h.lowestEquivalentValue(v) + h.sizeOfEquivalentValueRange(v)
|
||||
}
|
||||
|
||||
func (h *Histogram) highestEquivalentValue(v int64) int64 {
|
||||
return h.nextNonEquivalentValue(v) - 1
|
||||
}
|
||||
|
||||
func (h *Histogram) medianEquivalentValue(v int64) int64 {
|
||||
return h.lowestEquivalentValue(v) + (h.sizeOfEquivalentValueRange(v) >> 1)
|
||||
}
|
||||
|
||||
func (h *Histogram) getCountAtIndex(bucketIdx, subBucketIdx int32) int64 {
|
||||
return h.counts[h.countsIndex(bucketIdx, subBucketIdx)]
|
||||
}
|
||||
|
||||
func (h *Histogram) countsIndex(bucketIdx, subBucketIdx int32) int32 {
|
||||
bucketBaseIdx := (bucketIdx + 1) << uint(h.subBucketHalfCountMagnitude)
|
||||
offsetInBucket := subBucketIdx - h.subBucketHalfCount
|
||||
return bucketBaseIdx + offsetInBucket
|
||||
}
|
||||
|
||||
func (h *Histogram) getBucketIndex(v int64) int32 {
|
||||
pow2Ceiling := bitLen(v | h.subBucketMask)
|
||||
return int32(pow2Ceiling - int64(h.unitMagnitude) -
|
||||
int64(h.subBucketHalfCountMagnitude+1))
|
||||
}
|
||||
|
||||
func (h *Histogram) getSubBucketIdx(v int64, idx int32) int32 {
|
||||
return int32(v >> uint(int64(idx)+int64(h.unitMagnitude)))
|
||||
}
|
||||
|
||||
func (h *Histogram) countsIndexFor(v int64) int {
|
||||
bucketIdx := h.getBucketIndex(v)
|
||||
subBucketIdx := h.getSubBucketIdx(v, bucketIdx)
|
||||
return int(h.countsIndex(bucketIdx, subBucketIdx))
|
||||
}
|
||||
|
||||
type iterator struct {
|
||||
h *Histogram
|
||||
bucketIdx, subBucketIdx int32
|
||||
countAtIdx, countToIdx, valueFromIdx int64
|
||||
highestEquivalentValue int64
|
||||
}
|
||||
|
||||
func (i *iterator) next() bool {
|
||||
if i.countToIdx >= i.h.totalCount {
|
||||
return false
|
||||
}
|
||||
|
||||
// increment bucket
|
||||
i.subBucketIdx++
|
||||
if i.subBucketIdx >= i.h.subBucketCount {
|
||||
i.subBucketIdx = i.h.subBucketHalfCount
|
||||
i.bucketIdx++
|
||||
}
|
||||
|
||||
if i.bucketIdx >= i.h.bucketCount {
|
||||
return false
|
||||
}
|
||||
|
||||
i.countAtIdx = i.h.getCountAtIndex(i.bucketIdx, i.subBucketIdx)
|
||||
i.countToIdx += i.countAtIdx
|
||||
i.valueFromIdx = i.h.valueFromIndex(i.bucketIdx, i.subBucketIdx)
|
||||
i.highestEquivalentValue = i.h.highestEquivalentValue(i.valueFromIdx)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
type rIterator struct {
|
||||
iterator
|
||||
countAddedThisStep int64
|
||||
}
|
||||
|
||||
func (r *rIterator) next() bool {
|
||||
for r.iterator.next() {
|
||||
if r.countAtIdx != 0 {
|
||||
r.countAddedThisStep = r.countAtIdx
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type pIterator struct {
|
||||
iterator
|
||||
seenLastValue bool
|
||||
ticksPerHalfDistance int32
|
||||
percentileToIteratorTo float64
|
||||
percentile float64
|
||||
}
|
||||
|
||||
func (p *pIterator) next() bool {
|
||||
if !(p.countToIdx < p.h.totalCount) {
|
||||
if p.seenLastValue {
|
||||
return false
|
||||
}
|
||||
|
||||
p.seenLastValue = true
|
||||
p.percentile = 100
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
if p.subBucketIdx == -1 && !p.iterator.next() {
|
||||
return false
|
||||
}
|
||||
|
||||
var done = false
|
||||
for !done {
|
||||
currentPercentile := (100.0 * float64(p.countToIdx)) / float64(p.h.totalCount)
|
||||
if p.countAtIdx != 0 && p.percentileToIteratorTo <= currentPercentile {
|
||||
p.percentile = p.percentileToIteratorTo
|
||||
halfDistance := math.Trunc(math.Pow(2, math.Trunc(math.Log2(100.0/(100.0-p.percentileToIteratorTo)))+1))
|
||||
percentileReportingTicks := float64(p.ticksPerHalfDistance) * halfDistance
|
||||
p.percentileToIteratorTo += 100.0 / percentileReportingTicks
|
||||
return true
|
||||
}
|
||||
done = !p.iterator.next()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func bitLen(x int64) (n int64) {
|
||||
for ; x >= 0x8000; x >>= 16 {
|
||||
n += 16
|
||||
}
|
||||
if x >= 0x80 {
|
||||
x >>= 8
|
||||
n += 8
|
||||
}
|
||||
if x >= 0x8 {
|
||||
x >>= 4
|
||||
n += 4
|
||||
}
|
||||
if x >= 0x2 {
|
||||
x >>= 2
|
||||
n += 2
|
||||
}
|
||||
if x >= 0x1 {
|
||||
n++
|
||||
}
|
||||
return
|
||||
}
|
||||
333
Godeps/_workspace/src/github.com/codahale/hdrhistogram/hdr_test.go
generated
vendored
Normal file
333
Godeps/_workspace/src/github.com/codahale/hdrhistogram/hdr_test.go
generated
vendored
Normal file
@ -0,0 +1,333 @@
|
||||
package hdrhistogram_test
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/hdrhistogram"
|
||||
)
|
||||
|
||||
func TestHighSigFig(t *testing.T) {
|
||||
input := []int64{
|
||||
459876, 669187, 711612, 816326, 931423, 1033197, 1131895, 2477317,
|
||||
3964974, 12718782,
|
||||
}
|
||||
|
||||
hist := hdrhistogram.New(459876, 12718782, 5)
|
||||
for _, sample := range input {
|
||||
hist.RecordValue(sample)
|
||||
}
|
||||
|
||||
if v, want := hist.ValueAtQuantile(50), int64(1048575); v != want {
|
||||
t.Errorf("Median was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValueAtQuantile(t *testing.T) {
|
||||
h := hdrhistogram.New(1, 10000000, 3)
|
||||
|
||||
for i := 0; i < 1000000; i++ {
|
||||
if err := h.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
data := []struct {
|
||||
q float64
|
||||
v int64
|
||||
}{
|
||||
{q: 50, v: 500223},
|
||||
{q: 75, v: 750079},
|
||||
{q: 90, v: 900095},
|
||||
{q: 95, v: 950271},
|
||||
{q: 99, v: 990207},
|
||||
{q: 99.9, v: 999423},
|
||||
{q: 99.99, v: 999935},
|
||||
}
|
||||
|
||||
for _, d := range data {
|
||||
if v := h.ValueAtQuantile(d.q); v != d.v {
|
||||
t.Errorf("P%v was %v, but expected %v", d.q, v, d.v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMean(t *testing.T) {
|
||||
h := hdrhistogram.New(1, 10000000, 3)
|
||||
|
||||
for i := 0; i < 1000000; i++ {
|
||||
if err := h.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if v, want := h.Mean(), 500000.013312; v != want {
|
||||
t.Errorf("Mean was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStdDev(t *testing.T) {
|
||||
h := hdrhistogram.New(1, 10000000, 3)
|
||||
|
||||
for i := 0; i < 1000000; i++ {
|
||||
if err := h.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if v, want := h.StdDev(), 288675.1403682715; v != want {
|
||||
t.Errorf("StdDev was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotalCount(t *testing.T) {
|
||||
h := hdrhistogram.New(1, 10000000, 3)
|
||||
|
||||
for i := 0; i < 1000000; i++ {
|
||||
if err := h.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if v, want := h.TotalCount(), int64(i+1); v != want {
|
||||
t.Errorf("TotalCount was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMax(t *testing.T) {
|
||||
h := hdrhistogram.New(1, 10000000, 3)
|
||||
|
||||
for i := 0; i < 1000000; i++ {
|
||||
if err := h.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if v, want := h.Max(), int64(999936); v != want {
|
||||
t.Errorf("Max was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReset(t *testing.T) {
|
||||
h := hdrhistogram.New(1, 10000000, 3)
|
||||
|
||||
for i := 0; i < 1000000; i++ {
|
||||
if err := h.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
h.Reset()
|
||||
|
||||
if v, want := h.Max(), int64(0); v != want {
|
||||
t.Errorf("Max was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMerge(t *testing.T) {
|
||||
h1 := hdrhistogram.New(1, 1000, 3)
|
||||
h2 := hdrhistogram.New(1, 1000, 3)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
if err := h1.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 100; i < 200; i++ {
|
||||
if err := h2.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
h1.Merge(h2)
|
||||
|
||||
if v, want := h1.ValueAtQuantile(50), int64(99); v != want {
|
||||
t.Errorf("Median was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMin(t *testing.T) {
|
||||
h := hdrhistogram.New(1, 10000000, 3)
|
||||
|
||||
for i := 0; i < 1000000; i++ {
|
||||
if err := h.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if v, want := h.Min(), int64(0); v != want {
|
||||
t.Errorf("Min was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteSize(t *testing.T) {
|
||||
h := hdrhistogram.New(1, 100000, 3)
|
||||
|
||||
if v, want := h.ByteSize(), 65604; v != want {
|
||||
t.Errorf("ByteSize was %v, but expected %d", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecordCorrectedValue(t *testing.T) {
|
||||
h := hdrhistogram.New(1, 100000, 3)
|
||||
|
||||
if err := h.RecordCorrectedValue(10, 100); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if v, want := h.ValueAtQuantile(75), int64(10); v != want {
|
||||
t.Errorf("Corrected value was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecordCorrectedValueStall(t *testing.T) {
|
||||
h := hdrhistogram.New(1, 100000, 3)
|
||||
|
||||
if err := h.RecordCorrectedValue(1000, 100); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if v, want := h.ValueAtQuantile(75), int64(800); v != want {
|
||||
t.Errorf("Corrected value was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCumulativeDistribution(t *testing.T) {
|
||||
h := hdrhistogram.New(1, 100000000, 3)
|
||||
|
||||
for i := 0; i < 1000000; i++ {
|
||||
if err := h.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
actual := h.CumulativeDistribution()
|
||||
expected := []hdrhistogram.Bracket{
|
||||
hdrhistogram.Bracket{Quantile: 0, Count: 1, ValueAt: 0},
|
||||
hdrhistogram.Bracket{Quantile: 50, Count: 500224, ValueAt: 500223},
|
||||
hdrhistogram.Bracket{Quantile: 75, Count: 750080, ValueAt: 750079},
|
||||
hdrhistogram.Bracket{Quantile: 87.5, Count: 875008, ValueAt: 875007},
|
||||
hdrhistogram.Bracket{Quantile: 93.75, Count: 937984, ValueAt: 937983},
|
||||
hdrhistogram.Bracket{Quantile: 96.875, Count: 969216, ValueAt: 969215},
|
||||
hdrhistogram.Bracket{Quantile: 98.4375, Count: 984576, ValueAt: 984575},
|
||||
hdrhistogram.Bracket{Quantile: 99.21875, Count: 992256, ValueAt: 992255},
|
||||
hdrhistogram.Bracket{Quantile: 99.609375, Count: 996352, ValueAt: 996351},
|
||||
hdrhistogram.Bracket{Quantile: 99.8046875, Count: 998400, ValueAt: 998399},
|
||||
hdrhistogram.Bracket{Quantile: 99.90234375, Count: 999424, ValueAt: 999423},
|
||||
hdrhistogram.Bracket{Quantile: 99.951171875, Count: 999936, ValueAt: 999935},
|
||||
hdrhistogram.Bracket{Quantile: 99.9755859375, Count: 999936, ValueAt: 999935},
|
||||
hdrhistogram.Bracket{Quantile: 99.98779296875, Count: 999936, ValueAt: 999935},
|
||||
hdrhistogram.Bracket{Quantile: 99.993896484375, Count: 1000000, ValueAt: 1000447},
|
||||
hdrhistogram.Bracket{Quantile: 100, Count: 1000000, ValueAt: 1000447},
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(actual, expected) {
|
||||
t.Errorf("CF was %#v, but expected %#v", actual, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHistogramRecordValue(b *testing.B) {
|
||||
h := hdrhistogram.New(1, 10000000, 3)
|
||||
for i := 0; i < 1000000; i++ {
|
||||
if err := h.RecordValue(int64(i)); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
b.ResetTimer()
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
h.RecordValue(100)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkNew(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
hdrhistogram.New(1, 120000, 3) // this could track 1ms-2min
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnitMagnitudeOverflow(t *testing.T) {
|
||||
h := hdrhistogram.New(0, 200, 4)
|
||||
if err := h.RecordValue(11); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubBucketMaskOverflow(t *testing.T) {
|
||||
hist := hdrhistogram.New(2e7, 1e8, 5)
|
||||
for _, sample := range [...]int64{1e8, 2e7, 3e7} {
|
||||
hist.RecordValue(sample)
|
||||
}
|
||||
|
||||
for q, want := range map[float64]int64{
|
||||
50: 33554431,
|
||||
83.33: 33554431,
|
||||
83.34: 100663295,
|
||||
99: 100663295,
|
||||
} {
|
||||
if got := hist.ValueAtQuantile(q); got != want {
|
||||
t.Errorf("got %d for %fth percentile. want: %d", got, q, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExportImport(t *testing.T) {
|
||||
min := int64(1)
|
||||
max := int64(10000000)
|
||||
sigfigs := 3
|
||||
h := hdrhistogram.New(min, max, sigfigs)
|
||||
for i := 0; i < 1000000; i++ {
|
||||
if err := h.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
s := h.Export()
|
||||
|
||||
if v := s.LowestTrackableValue; v != min {
|
||||
t.Errorf("LowestTrackableValue was %v, but expected %v", v, min)
|
||||
}
|
||||
|
||||
if v := s.HighestTrackableValue; v != max {
|
||||
t.Errorf("HighestTrackableValue was %v, but expected %v", v, max)
|
||||
}
|
||||
|
||||
if v := int(s.SignificantFigures); v != sigfigs {
|
||||
t.Errorf("SignificantFigures was %v, but expected %v", v, sigfigs)
|
||||
}
|
||||
|
||||
if imported := hdrhistogram.Import(s); !imported.Equals(h) {
|
||||
t.Error("Expected Histograms to be equivalent")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestEquals(t *testing.T) {
|
||||
h1 := hdrhistogram.New(1, 10000000, 3)
|
||||
for i := 0; i < 1000000; i++ {
|
||||
if err := h1.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
h2 := hdrhistogram.New(1, 10000000, 3)
|
||||
for i := 0; i < 10000; i++ {
|
||||
if err := h1.RecordValue(int64(i)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if h1.Equals(h2) {
|
||||
t.Error("Expected Histograms to not be equivalent")
|
||||
}
|
||||
|
||||
h1.Reset()
|
||||
h2.Reset()
|
||||
|
||||
if !h1.Equals(h2) {
|
||||
t.Error("Expected Histograms to be equivalent")
|
||||
}
|
||||
}
|
||||
45
Godeps/_workspace/src/github.com/codahale/hdrhistogram/window.go
generated
vendored
Normal file
45
Godeps/_workspace/src/github.com/codahale/hdrhistogram/window.go
generated
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
package hdrhistogram
|
||||
|
||||
// A WindowedHistogram combines histograms to provide windowed statistics.
|
||||
type WindowedHistogram struct {
|
||||
idx int
|
||||
h []Histogram
|
||||
m *Histogram
|
||||
|
||||
Current *Histogram
|
||||
}
|
||||
|
||||
// NewWindowed creates a new WindowedHistogram with N underlying histograms with
|
||||
// the given parameters.
|
||||
func NewWindowed(n int, minValue, maxValue int64, sigfigs int) *WindowedHistogram {
|
||||
w := WindowedHistogram{
|
||||
idx: -1,
|
||||
h: make([]Histogram, n),
|
||||
m: New(minValue, maxValue, sigfigs),
|
||||
}
|
||||
|
||||
for i := range w.h {
|
||||
w.h[i] = *New(minValue, maxValue, sigfigs)
|
||||
}
|
||||
w.Rotate()
|
||||
|
||||
return &w
|
||||
}
|
||||
|
||||
// Merge returns a histogram which includes the recorded values from all the
|
||||
// sections of the window.
|
||||
func (w *WindowedHistogram) Merge() *Histogram {
|
||||
w.m.Reset()
|
||||
for _, h := range w.h {
|
||||
w.m.Merge(&h)
|
||||
}
|
||||
return w.m
|
||||
}
|
||||
|
||||
// Rotate resets the oldest histogram and rotates it to be used as the current
|
||||
// histogram.
|
||||
func (w *WindowedHistogram) Rotate() {
|
||||
w.idx++
|
||||
w.Current = &w.h[w.idx%len(w.h)]
|
||||
w.Current.Reset()
|
||||
}
|
||||
64
Godeps/_workspace/src/github.com/codahale/hdrhistogram/window_test.go
generated
vendored
Normal file
64
Godeps/_workspace/src/github.com/codahale/hdrhistogram/window_test.go
generated
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
package hdrhistogram_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/hdrhistogram"
|
||||
)
|
||||
|
||||
func TestWindowedHistogram(t *testing.T) {
|
||||
w := hdrhistogram.NewWindowed(2, 1, 1000, 3)
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
w.Current.RecordValue(int64(i))
|
||||
}
|
||||
w.Rotate()
|
||||
|
||||
for i := 100; i < 200; i++ {
|
||||
w.Current.RecordValue(int64(i))
|
||||
}
|
||||
w.Rotate()
|
||||
|
||||
for i := 200; i < 300; i++ {
|
||||
w.Current.RecordValue(int64(i))
|
||||
}
|
||||
|
||||
if v, want := w.Merge().ValueAtQuantile(50), int64(199); v != want {
|
||||
t.Errorf("Median was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWindowedHistogramRecordAndRotate(b *testing.B) {
|
||||
w := hdrhistogram.NewWindowed(3, 1, 10000000, 3)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
if err := w.Current.RecordValue(100); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
if i%100000 == 1 {
|
||||
w.Rotate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkWindowedHistogramMerge(b *testing.B) {
|
||||
w := hdrhistogram.NewWindowed(3, 1, 10000000, 3)
|
||||
for i := 0; i < 10000000; i++ {
|
||||
if err := w.Current.RecordValue(100); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
||||
if i%100000 == 1 {
|
||||
w.Rotate()
|
||||
}
|
||||
}
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
w.Merge()
|
||||
}
|
||||
}
|
||||
9
Godeps/_workspace/src/github.com/codahale/metrics/.travis.yml
generated
vendored
Normal file
9
Godeps/_workspace/src/github.com/codahale/metrics/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.3.3
|
||||
notifications:
|
||||
# See http://about.travis-ci.org/docs/user/build-configuration/ to learn more
|
||||
# about configuring notification recipients and more.
|
||||
email:
|
||||
recipients:
|
||||
- coda.hale@gmail.com
|
||||
21
Godeps/_workspace/src/github.com/codahale/metrics/LICENSE
generated
vendored
Normal file
21
Godeps/_workspace/src/github.com/codahale/metrics/LICENSE
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Coda Hale
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
8
Godeps/_workspace/src/github.com/codahale/metrics/README.md
generated
vendored
Normal file
8
Godeps/_workspace/src/github.com/codahale/metrics/README.md
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
metrics
|
||||
=======
|
||||
|
||||
[](https://travis-ci.org/codahale/metrics)
|
||||
|
||||
A Go library which provides light-weight instrumentation for your application.
|
||||
|
||||
For documentation, check [godoc](http://godoc.org/github.com/codahale/metrics).
|
||||
329
Godeps/_workspace/src/github.com/codahale/metrics/metrics.go
generated
vendored
Normal file
329
Godeps/_workspace/src/github.com/codahale/metrics/metrics.go
generated
vendored
Normal file
@ -0,0 +1,329 @@
|
||||
// Package metrics provides minimalist instrumentation for your applications in
|
||||
// the form of counters and gauges.
|
||||
//
|
||||
// Counters
|
||||
//
|
||||
// A counter is a monotonically-increasing, unsigned, 64-bit integer used to
|
||||
// represent the number of times an event has occurred. By tracking the deltas
|
||||
// between measurements of a counter over intervals of time, an aggregation
|
||||
// layer can derive rates, acceleration, etc.
|
||||
//
|
||||
// Gauges
|
||||
//
|
||||
// A gauge returns instantaneous measurements of something using signed, 64-bit
|
||||
// integers. This value does not need to be monotonic.
|
||||
//
|
||||
// Histograms
|
||||
//
|
||||
// A histogram tracks the distribution of a stream of values (e.g. the number of
|
||||
// milliseconds it takes to handle requests), adding gauges for the values at
|
||||
// meaningful quantiles: 50th, 75th, 90th, 95th, 99th, 99.9th.
|
||||
//
|
||||
// Reporting
|
||||
//
|
||||
// Measurements from counters and gauges are available as expvars. Your service
|
||||
// should return its expvars from an HTTP endpoint (i.e., /debug/vars) as a JSON
|
||||
// object.
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"expvar"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/hdrhistogram"
|
||||
)
|
||||
|
||||
// A Counter is a monotonically increasing unsigned integer.
|
||||
//
|
||||
// Use a counter to derive rates (e.g., record total number of requests, derive
|
||||
// requests per second).
|
||||
type Counter string
|
||||
|
||||
// Add increments the counter by one.
|
||||
func (c Counter) Add() {
|
||||
c.AddN(1)
|
||||
}
|
||||
|
||||
// AddN increments the counter by N.
|
||||
func (c Counter) AddN(delta uint64) {
|
||||
cm.Lock()
|
||||
counters[string(c)] += delta
|
||||
cm.Unlock()
|
||||
}
|
||||
|
||||
// SetFunc sets the counter's value to the lazily-called return value of the
|
||||
// given function.
|
||||
func (c Counter) SetFunc(f func() uint64) {
|
||||
cm.Lock()
|
||||
defer cm.Unlock()
|
||||
|
||||
counterFuncs[string(c)] = f
|
||||
}
|
||||
|
||||
// SetBatchFunc sets the counter's value to the lazily-called return value of
|
||||
// the given function, with an additional initializer function for a related
|
||||
// batch of counters, all of which are keyed by an arbitrary value.
|
||||
func (c Counter) SetBatchFunc(key interface{}, init func(), f func() uint64) {
|
||||
cm.Lock()
|
||||
defer cm.Unlock()
|
||||
|
||||
gm.Lock()
|
||||
defer gm.Unlock()
|
||||
|
||||
counterFuncs[string(c)] = f
|
||||
if _, ok := inits[key]; !ok {
|
||||
inits[key] = init
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes the given counter.
|
||||
func (c Counter) Remove() {
|
||||
cm.Lock()
|
||||
defer cm.Unlock()
|
||||
|
||||
gm.Lock()
|
||||
defer gm.Unlock()
|
||||
|
||||
delete(counters, string(c))
|
||||
delete(counterFuncs, string(c))
|
||||
delete(inits, string(c))
|
||||
}
|
||||
|
||||
// A Gauge is an instantaneous measurement of a value.
|
||||
//
|
||||
// Use a gauge to track metrics which increase and decrease (e.g., amount of
|
||||
// free memory).
|
||||
type Gauge string
|
||||
|
||||
// Set the gauge's value to the given value.
|
||||
func (g Gauge) Set(value int64) {
|
||||
gm.Lock()
|
||||
defer gm.Unlock()
|
||||
|
||||
gauges[string(g)] = func() int64 {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
// SetFunc sets the gauge's value to the lazily-called return value of the given
|
||||
// function.
|
||||
func (g Gauge) SetFunc(f func() int64) {
|
||||
gm.Lock()
|
||||
defer gm.Unlock()
|
||||
|
||||
gauges[string(g)] = f
|
||||
}
|
||||
|
||||
// SetBatchFunc sets the gauge's value to the lazily-called return value of the
|
||||
// given function, with an additional initializer function for a related batch
|
||||
// of gauges, all of which are keyed by an arbitrary value.
|
||||
func (g Gauge) SetBatchFunc(key interface{}, init func(), f func() int64) {
|
||||
gm.Lock()
|
||||
defer gm.Unlock()
|
||||
|
||||
gauges[string(g)] = f
|
||||
if _, ok := inits[key]; !ok {
|
||||
inits[key] = init
|
||||
}
|
||||
}
|
||||
|
||||
// Remove removes the given gauge.
|
||||
func (g Gauge) Remove() {
|
||||
gm.Lock()
|
||||
defer gm.Unlock()
|
||||
|
||||
delete(gauges, string(g))
|
||||
delete(inits, string(g))
|
||||
}
|
||||
|
||||
// Reset removes all existing counters and gauges.
|
||||
func Reset() {
|
||||
cm.Lock()
|
||||
defer cm.Unlock()
|
||||
|
||||
gm.Lock()
|
||||
defer gm.Unlock()
|
||||
|
||||
hm.Lock()
|
||||
defer hm.Unlock()
|
||||
|
||||
counters = make(map[string]uint64)
|
||||
counterFuncs = make(map[string]func() uint64)
|
||||
gauges = make(map[string]func() int64)
|
||||
histograms = make(map[string]*Histogram)
|
||||
inits = make(map[interface{}]func())
|
||||
}
|
||||
|
||||
// Snapshot returns a copy of the values of all registered counters and gauges.
|
||||
func Snapshot() (c map[string]uint64, g map[string]int64) {
|
||||
cm.Lock()
|
||||
defer cm.Unlock()
|
||||
|
||||
gm.Lock()
|
||||
defer gm.Unlock()
|
||||
|
||||
hm.Lock()
|
||||
defer hm.Unlock()
|
||||
|
||||
for _, init := range inits {
|
||||
init()
|
||||
}
|
||||
|
||||
c = make(map[string]uint64, len(counters)+len(counterFuncs))
|
||||
for n, v := range counters {
|
||||
c[n] = v
|
||||
}
|
||||
|
||||
for n, f := range counterFuncs {
|
||||
c[n] = f()
|
||||
}
|
||||
|
||||
g = make(map[string]int64, len(gauges))
|
||||
for n, f := range gauges {
|
||||
g[n] = f()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewHistogram returns a windowed HDR histogram which drops data older than
|
||||
// five minutes. The returned histogram is safe to use from multiple goroutines.
|
||||
//
|
||||
// Use a histogram to track the distribution of a stream of values (e.g., the
|
||||
// latency associated with HTTP requests).
|
||||
func NewHistogram(name string, minValue, maxValue int64, sigfigs int) *Histogram {
|
||||
hm.Lock()
|
||||
defer hm.Unlock()
|
||||
|
||||
if _, ok := histograms[name]; ok {
|
||||
panic(name + " already exists")
|
||||
}
|
||||
|
||||
hist := &Histogram{
|
||||
name: name,
|
||||
hist: hdrhistogram.NewWindowed(5, minValue, maxValue, sigfigs),
|
||||
}
|
||||
histograms[name] = hist
|
||||
|
||||
Gauge(name+".P50").SetBatchFunc(hname(name), hist.merge, hist.valueAt(50))
|
||||
Gauge(name+".P75").SetBatchFunc(hname(name), hist.merge, hist.valueAt(75))
|
||||
Gauge(name+".P90").SetBatchFunc(hname(name), hist.merge, hist.valueAt(90))
|
||||
Gauge(name+".P95").SetBatchFunc(hname(name), hist.merge, hist.valueAt(95))
|
||||
Gauge(name+".P99").SetBatchFunc(hname(name), hist.merge, hist.valueAt(99))
|
||||
Gauge(name+".P999").SetBatchFunc(hname(name), hist.merge, hist.valueAt(99.9))
|
||||
|
||||
return hist
|
||||
}
|
||||
|
||||
// Remove removes the given histogram.
|
||||
func (h *Histogram) Remove() {
|
||||
|
||||
hm.Lock()
|
||||
defer hm.Unlock()
|
||||
|
||||
Gauge(h.name + ".P50").Remove()
|
||||
Gauge(h.name + ".P75").Remove()
|
||||
Gauge(h.name + ".P90").Remove()
|
||||
Gauge(h.name + ".P95").Remove()
|
||||
Gauge(h.name + ".P99").Remove()
|
||||
Gauge(h.name + ".P999").Remove()
|
||||
|
||||
delete(histograms, h.name)
|
||||
}
|
||||
|
||||
type hname string // unexported to prevent collisions
|
||||
|
||||
// A Histogram measures the distribution of a stream of values.
|
||||
type Histogram struct {
|
||||
name string
|
||||
hist *hdrhistogram.WindowedHistogram
|
||||
m *hdrhistogram.Histogram
|
||||
rw sync.RWMutex
|
||||
}
|
||||
|
||||
// Name returns the name of the histogram
|
||||
func (h *Histogram) Name() string {
|
||||
return h.name
|
||||
}
|
||||
|
||||
// RecordValue records the given value, or returns an error if the value is out
|
||||
// of range.
|
||||
// Returned error values are of type Error.
|
||||
func (h *Histogram) RecordValue(v int64) error {
|
||||
h.rw.Lock()
|
||||
defer h.rw.Unlock()
|
||||
|
||||
err := h.hist.Current.RecordValue(v)
|
||||
if err != nil {
|
||||
return Error{h.name, err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Histogram) rotate() {
|
||||
h.rw.Lock()
|
||||
defer h.rw.Unlock()
|
||||
|
||||
h.hist.Rotate()
|
||||
}
|
||||
|
||||
func (h *Histogram) merge() {
|
||||
h.rw.Lock()
|
||||
defer h.rw.Unlock()
|
||||
|
||||
h.m = h.hist.Merge()
|
||||
}
|
||||
|
||||
func (h *Histogram) valueAt(q float64) func() int64 {
|
||||
return func() int64 {
|
||||
h.rw.RLock()
|
||||
defer h.rw.RUnlock()
|
||||
|
||||
if h.m == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return h.m.ValueAtQuantile(q)
|
||||
}
|
||||
}
|
||||
|
||||
// Error describes an error and the name of the metric where it occurred.
|
||||
type Error struct {
|
||||
Metric string
|
||||
Err error
|
||||
}
|
||||
|
||||
func (e Error) Error() string {
|
||||
return e.Metric + ": " + e.Err.Error()
|
||||
}
|
||||
|
||||
var (
|
||||
counters = make(map[string]uint64)
|
||||
counterFuncs = make(map[string]func() uint64)
|
||||
gauges = make(map[string]func() int64)
|
||||
inits = make(map[interface{}]func())
|
||||
histograms = make(map[string]*Histogram)
|
||||
|
||||
cm, gm, hm sync.Mutex
|
||||
)
|
||||
|
||||
func init() {
|
||||
expvar.Publish("metrics", expvar.Func(func() interface{} {
|
||||
counters, gauges := Snapshot()
|
||||
return map[string]interface{}{
|
||||
"Counters": counters,
|
||||
"Gauges": gauges,
|
||||
}
|
||||
}))
|
||||
|
||||
go func() {
|
||||
for _ = range time.NewTicker(1 * time.Minute).C {
|
||||
hm.Lock()
|
||||
for _, h := range histograms {
|
||||
h.rotate()
|
||||
}
|
||||
hm.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
217
Godeps/_workspace/src/github.com/codahale/metrics/metrics_test.go
generated
vendored
Normal file
217
Godeps/_workspace/src/github.com/codahale/metrics/metrics_test.go
generated
vendored
Normal file
@ -0,0 +1,217 @@
|
||||
package metrics_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/metrics"
|
||||
)
|
||||
|
||||
func TestCounter(t *testing.T) {
|
||||
metrics.Reset()
|
||||
|
||||
metrics.Counter("whee").Add()
|
||||
metrics.Counter("whee").AddN(10)
|
||||
|
||||
counters, _ := metrics.Snapshot()
|
||||
if v, want := counters["whee"], uint64(11); v != want {
|
||||
t.Errorf("Counter was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCounterFunc(t *testing.T) {
|
||||
metrics.Reset()
|
||||
|
||||
metrics.Counter("whee").SetFunc(func() uint64 {
|
||||
return 100
|
||||
})
|
||||
|
||||
counters, _ := metrics.Snapshot()
|
||||
if v, want := counters["whee"], uint64(100); v != want {
|
||||
t.Errorf("Counter was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCounterBatchFunc(t *testing.T) {
|
||||
metrics.Reset()
|
||||
|
||||
var a, b uint64
|
||||
|
||||
metrics.Counter("whee").SetBatchFunc(
|
||||
"yay",
|
||||
func() {
|
||||
a, b = 1, 2
|
||||
},
|
||||
func() uint64 {
|
||||
return a
|
||||
},
|
||||
)
|
||||
|
||||
metrics.Counter("woo").SetBatchFunc(
|
||||
"yay",
|
||||
func() {
|
||||
a, b = 1, 2
|
||||
},
|
||||
func() uint64 {
|
||||
return b
|
||||
},
|
||||
)
|
||||
|
||||
counters, _ := metrics.Snapshot()
|
||||
if v, want := counters["whee"], uint64(1); v != want {
|
||||
t.Errorf("Counter was %v, but expected %v", v, want)
|
||||
}
|
||||
|
||||
if v, want := counters["woo"], uint64(2); v != want {
|
||||
t.Errorf("Counter was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCounterRemove(t *testing.T) {
|
||||
metrics.Reset()
|
||||
|
||||
metrics.Counter("whee").Add()
|
||||
metrics.Counter("whee").Remove()
|
||||
|
||||
counters, _ := metrics.Snapshot()
|
||||
if v, ok := counters["whee"]; ok {
|
||||
t.Errorf("Counter was %v, but expected nothing", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGaugeValue(t *testing.T) {
|
||||
metrics.Reset()
|
||||
|
||||
metrics.Gauge("whee").Set(-100)
|
||||
|
||||
_, gauges := metrics.Snapshot()
|
||||
if v, want := gauges["whee"], int64(-100); v != want {
|
||||
t.Errorf("Gauge was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGaugeFunc(t *testing.T) {
|
||||
metrics.Reset()
|
||||
|
||||
metrics.Gauge("whee").SetFunc(func() int64 {
|
||||
return -100
|
||||
})
|
||||
|
||||
_, gauges := metrics.Snapshot()
|
||||
if v, want := gauges["whee"], int64(-100); v != want {
|
||||
t.Errorf("Gauge was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGaugeRemove(t *testing.T) {
|
||||
metrics.Reset()
|
||||
|
||||
metrics.Gauge("whee").Set(1)
|
||||
metrics.Gauge("whee").Remove()
|
||||
|
||||
_, gauges := metrics.Snapshot()
|
||||
if v, ok := gauges["whee"]; ok {
|
||||
t.Errorf("Gauge was %v, but expected nothing", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHistogram(t *testing.T) {
|
||||
metrics.Reset()
|
||||
|
||||
h := metrics.NewHistogram("heyo", 1, 1000, 3)
|
||||
for i := 100; i > 0; i-- {
|
||||
for j := 0; j < i; j++ {
|
||||
h.RecordValue(int64(i))
|
||||
}
|
||||
}
|
||||
|
||||
_, gauges := metrics.Snapshot()
|
||||
|
||||
if v, want := gauges["heyo.P50"], int64(71); v != want {
|
||||
t.Errorf("P50 was %v, but expected %v", v, want)
|
||||
}
|
||||
|
||||
if v, want := gauges["heyo.P75"], int64(87); v != want {
|
||||
t.Errorf("P75 was %v, but expected %v", v, want)
|
||||
}
|
||||
|
||||
if v, want := gauges["heyo.P90"], int64(95); v != want {
|
||||
t.Errorf("P90 was %v, but expected %v", v, want)
|
||||
}
|
||||
|
||||
if v, want := gauges["heyo.P95"], int64(98); v != want {
|
||||
t.Errorf("P95 was %v, but expected %v", v, want)
|
||||
}
|
||||
|
||||
if v, want := gauges["heyo.P99"], int64(100); v != want {
|
||||
t.Errorf("P99 was %v, but expected %v", v, want)
|
||||
}
|
||||
|
||||
if v, want := gauges["heyo.P999"], int64(100); v != want {
|
||||
t.Errorf("P999 was %v, but expected %v", v, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHistogramRemove(t *testing.T) {
|
||||
metrics.Reset()
|
||||
|
||||
h := metrics.NewHistogram("heyo", 1, 1000, 3)
|
||||
h.Remove()
|
||||
|
||||
_, gauges := metrics.Snapshot()
|
||||
if v, ok := gauges["heyo.P50"]; ok {
|
||||
t.Errorf("Gauge was %v, but expected nothing", v)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCounterAdd(b *testing.B) {
|
||||
metrics.Reset()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
metrics.Counter("test1").Add()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkCounterAddN(b *testing.B) {
|
||||
metrics.Reset()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
metrics.Counter("test2").AddN(100)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkGaugeSet(b *testing.B) {
|
||||
metrics.Reset()
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
metrics.Gauge("test2").Set(100)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkHistogramRecordValue(b *testing.B) {
|
||||
metrics.Reset()
|
||||
h := metrics.NewHistogram("hist", 1, 1000, 3)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
b.RunParallel(func(pb *testing.PB) {
|
||||
for pb.Next() {
|
||||
h.RecordValue(100)
|
||||
}
|
||||
})
|
||||
}
|
||||
18
Godeps/_workspace/src/github.com/codahale/metrics/runtime/doc.go
generated
vendored
Normal file
18
Godeps/_workspace/src/github.com/codahale/metrics/runtime/doc.go
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
// Package runtime registers gauges and counters for various operationally
|
||||
// important aspects of the Go runtime.
|
||||
//
|
||||
// To use, import this package:
|
||||
//
|
||||
// import _ "github.com/codahale/metrics/runtime"
|
||||
//
|
||||
// This registers the following gauges:
|
||||
//
|
||||
// FileDescriptors.Max
|
||||
// FileDescriptors.Used
|
||||
// Mem.NumGC
|
||||
// Mem.PauseTotalNs
|
||||
// Mem.LastGC
|
||||
// Mem.Alloc
|
||||
// Mem.HeapObjects
|
||||
// Goroutines.Num
|
||||
package runtime
|
||||
44
Godeps/_workspace/src/github.com/codahale/metrics/runtime/fds.go
generated
vendored
Normal file
44
Godeps/_workspace/src/github.com/codahale/metrics/runtime/fds.go
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
// +build !windows
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"syscall"
|
||||
|
||||
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/metrics"
|
||||
)
|
||||
|
||||
func getFDLimit() (uint64, error) {
|
||||
var rlimit syscall.Rlimit
|
||||
if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return rlimit.Cur, nil
|
||||
}
|
||||
|
||||
func getFDUsage() (uint64, error) {
|
||||
fds, err := ioutil.ReadDir("/proc/self/fd")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return uint64(len(fds)), nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
metrics.Gauge("FileDescriptors.Max").SetFunc(func() int64 {
|
||||
v, err := getFDLimit()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return int64(v)
|
||||
})
|
||||
|
||||
metrics.Gauge("FileDescriptors.Used").SetFunc(func() int64 {
|
||||
v, err := getFDUsage()
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return int64(v)
|
||||
})
|
||||
}
|
||||
24
Godeps/_workspace/src/github.com/codahale/metrics/runtime/fds_test.go
generated
vendored
Normal file
24
Godeps/_workspace/src/github.com/codahale/metrics/runtime/fds_test.go
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
// +build !windows
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/metrics"
|
||||
)
|
||||
|
||||
func TestFdStats(t *testing.T) {
|
||||
_, gauges := metrics.Snapshot()
|
||||
|
||||
expected := []string{
|
||||
"FileDescriptors.Max",
|
||||
"FileDescriptors.Used",
|
||||
}
|
||||
|
||||
for _, name := range expected {
|
||||
if _, ok := gauges[name]; !ok {
|
||||
t.Errorf("Missing gauge %q", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
4
Godeps/_workspace/src/github.com/codahale/metrics/runtime/fds_windows.go
generated
vendored
Normal file
4
Godeps/_workspace/src/github.com/codahale/metrics/runtime/fds_windows.go
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
package runtime
|
||||
|
||||
func init() {
|
||||
}
|
||||
13
Godeps/_workspace/src/github.com/codahale/metrics/runtime/goroutines.go
generated
vendored
Normal file
13
Godeps/_workspace/src/github.com/codahale/metrics/runtime/goroutines.go
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/metrics"
|
||||
)
|
||||
|
||||
func init() {
|
||||
metrics.Gauge("Goroutines.Num").SetFunc(func() int64 {
|
||||
return int64(runtime.NumGoroutine())
|
||||
})
|
||||
}
|
||||
21
Godeps/_workspace/src/github.com/codahale/metrics/runtime/goroutines_test.go
generated
vendored
Normal file
21
Godeps/_workspace/src/github.com/codahale/metrics/runtime/goroutines_test.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/metrics"
|
||||
)
|
||||
|
||||
func TestGoroutinesStats(t *testing.T) {
|
||||
_, gauges := metrics.Snapshot()
|
||||
|
||||
expected := []string{
|
||||
"Goroutines.Num",
|
||||
}
|
||||
|
||||
for _, name := range expected {
|
||||
if _, ok := gauges[name]; !ok {
|
||||
t.Errorf("Missing gauge %q", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Godeps/_workspace/src/github.com/codahale/metrics/runtime/memstats.go
generated
vendored
Normal file
48
Godeps/_workspace/src/github.com/codahale/metrics/runtime/memstats.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/metrics"
|
||||
)
|
||||
|
||||
func init() {
|
||||
msg := &memStatGauges{}
|
||||
|
||||
metrics.Counter("Mem.NumGC").SetBatchFunc(key{}, msg.init, msg.numGC)
|
||||
metrics.Counter("Mem.PauseTotalNs").SetBatchFunc(key{}, msg.init, msg.totalPause)
|
||||
|
||||
metrics.Gauge("Mem.LastGC").SetBatchFunc(key{}, msg.init, msg.lastPause)
|
||||
metrics.Gauge("Mem.Alloc").SetBatchFunc(key{}, msg.init, msg.alloc)
|
||||
metrics.Gauge("Mem.HeapObjects").SetBatchFunc(key{}, msg.init, msg.objects)
|
||||
}
|
||||
|
||||
type key struct{} // unexported to prevent collision
|
||||
|
||||
type memStatGauges struct {
|
||||
stats runtime.MemStats
|
||||
}
|
||||
|
||||
func (msg *memStatGauges) init() {
|
||||
runtime.ReadMemStats(&msg.stats)
|
||||
}
|
||||
|
||||
func (msg *memStatGauges) numGC() uint64 {
|
||||
return uint64(msg.stats.NumGC)
|
||||
}
|
||||
|
||||
func (msg *memStatGauges) totalPause() uint64 {
|
||||
return msg.stats.PauseTotalNs
|
||||
}
|
||||
|
||||
func (msg *memStatGauges) lastPause() int64 {
|
||||
return int64(msg.stats.LastGC)
|
||||
}
|
||||
|
||||
func (msg *memStatGauges) alloc() int64 {
|
||||
return int64(msg.stats.Alloc)
|
||||
}
|
||||
|
||||
func (msg *memStatGauges) objects() int64 {
|
||||
return int64(msg.stats.HeapObjects)
|
||||
}
|
||||
34
Godeps/_workspace/src/github.com/codahale/metrics/runtime/memstats_test.go
generated
vendored
Normal file
34
Godeps/_workspace/src/github.com/codahale/metrics/runtime/memstats_test.go
generated
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/codahale/metrics"
|
||||
)
|
||||
|
||||
func TestMemStats(t *testing.T) {
|
||||
counters, gauges := metrics.Snapshot()
|
||||
|
||||
expectedCounters := []string{
|
||||
"Mem.NumGC",
|
||||
"Mem.PauseTotalNs",
|
||||
}
|
||||
|
||||
expectedGauges := []string{
|
||||
"Mem.LastGC",
|
||||
"Mem.Alloc",
|
||||
"Mem.HeapObjects",
|
||||
}
|
||||
|
||||
for _, name := range expectedCounters {
|
||||
if _, ok := counters[name]; !ok {
|
||||
t.Errorf("Missing counters %q", name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range expectedGauges {
|
||||
if _, ok := gauges[name]; !ok {
|
||||
t.Errorf("Missing gauge %q", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user