mirror of https://github.com/golang/go.git
expvar: swap Float sync. from mutex to atomic.
Float type from a mutex to atomic bit array in a manner akin to Google Guava's AtomicDouble[0], including adding a benchmark for the type (benchcmp included below) along with some expvar_test.go cruft being fixed. benchmark old ns/op new ns/op delta BenchmarkFloatSet 115 9.37 -91.85% BenchmarkFloatAdd 114 17.1 -85.00% benchmark old allocs new allocs delta BenchmarkFloatSet 0 0 +0.00% BenchmarkFloatAdd 0 0 +0.00% benchmark old bytes new bytes delta BenchmarkFloatSet 0 0 +0.00% BenchmarkFloatAdd 0 0 +0.00% [0] - http://goo.gl/m4dtlI Change-Id: I4ce6a913734ec692e3ed243f6e6f7c11da4c6036 Reviewed-on: https://go-review.googlesource.com/3687 Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
parent
ae740a459e
commit
926616da3f
|
|
@ -26,6 +26,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
|
|
@ -59,28 +60,30 @@ func (v *Int) Set(value int64) {
|
|||
|
||||
// Float is a 64-bit float variable that satisfies the Var interface.
|
||||
type Float struct {
|
||||
mu sync.RWMutex
|
||||
f float64
|
||||
f uint64
|
||||
}
|
||||
|
||||
func (v *Float) String() string {
|
||||
v.mu.RLock()
|
||||
defer v.mu.RUnlock()
|
||||
return strconv.FormatFloat(v.f, 'g', -1, 64)
|
||||
return strconv.FormatFloat(
|
||||
math.Float64frombits(atomic.LoadUint64(&v.f)), 'g', -1, 64)
|
||||
}
|
||||
|
||||
// Add adds delta to v.
|
||||
func (v *Float) Add(delta float64) {
|
||||
v.mu.Lock()
|
||||
defer v.mu.Unlock()
|
||||
v.f += delta
|
||||
for {
|
||||
cur := atomic.LoadUint64(&v.f)
|
||||
curVal := math.Float64frombits(cur)
|
||||
nxtVal := curVal + delta
|
||||
nxt := math.Float64bits(nxtVal)
|
||||
if atomic.CompareAndSwapUint64(&v.f, cur, nxt) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets v to value.
|
||||
func (v *Float) Set(value float64) {
|
||||
v.mu.Lock()
|
||||
defer v.mu.Unlock()
|
||||
v.f = value
|
||||
atomic.StoreUint64(&v.f, math.Float64bits(value))
|
||||
}
|
||||
|
||||
// Map is a string-to-Var map variable that satisfies the Var interface.
|
||||
|
|
|
|||
|
|
@ -7,11 +7,13 @@ package expvar
|
|||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"net"
|
||||
"net/http/httptest"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -70,6 +72,10 @@ func BenchmarkIntSet(b *testing.B) {
|
|||
})
|
||||
}
|
||||
|
||||
func (v *Float) val() float64 {
|
||||
return math.Float64frombits(atomic.LoadUint64(&v.f))
|
||||
}
|
||||
|
||||
func TestFloat(t *testing.T) {
|
||||
RemoveAll()
|
||||
reqs := NewFloat("requests-float")
|
||||
|
|
@ -82,8 +88,8 @@ func TestFloat(t *testing.T) {
|
|||
|
||||
reqs.Add(1.5)
|
||||
reqs.Add(1.25)
|
||||
if reqs.f != 2.75 {
|
||||
t.Errorf("reqs.f = %v, want 2.75", reqs.f)
|
||||
if v := reqs.val(); v != 2.75 {
|
||||
t.Errorf("reqs.val() = %v, want 2.75", v)
|
||||
}
|
||||
|
||||
if s := reqs.String(); s != "2.75" {
|
||||
|
|
@ -91,8 +97,8 @@ func TestFloat(t *testing.T) {
|
|||
}
|
||||
|
||||
reqs.Add(-2)
|
||||
if reqs.f != 0.75 {
|
||||
t.Errorf("reqs.f = %v, want 0.75", reqs.f)
|
||||
if v := reqs.val(); v != 0.75 {
|
||||
t.Errorf("reqs.val() = %v, want 0.75", v)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -157,8 +163,8 @@ func TestMapCounter(t *testing.T) {
|
|||
if x := colors.m["blue"].(*Int).i; x != 4 {
|
||||
t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
|
||||
}
|
||||
if x := colors.m[`green "midori"`].(*Float).f; x != 4.125 {
|
||||
t.Errorf("colors.m[`green \"midori\"] = %v, want 3.14", x)
|
||||
if x := colors.m[`green "midori"`].(*Float).val(); x != 4.125 {
|
||||
t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x)
|
||||
}
|
||||
|
||||
// colors.String() should be '{"red":3, "blue":4}',
|
||||
|
|
|
|||
Loading…
Reference in New Issue