aboutsummaryrefslogtreecommitdiff
path: root/src/expvar
diff options
context:
space:
mode:
authorMatt T. Proud <matt.proud@gmail.com>2015-02-02 00:33:44 -0800
committerRob Pike <r@golang.org>2015-04-12 23:07:50 +0000
commit926616da3f3781f5f71dacac429c6957dec83a65 (patch)
tree42a35dc0c3dc7d1e20e58ea2840ee7e5ce98843a /src/expvar
parentae740a459ef40f63d3a2864b70c89e316efd0c8b (diff)
downloadgo-926616da3f3781f5f71dacac429c6957dec83a65.tar.gz
go-926616da3f3781f5f71dacac429c6957dec83a65.zip
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>
Diffstat (limited to 'src/expvar')
-rw-r--r--src/expvar/expvar.go25
-rw-r--r--src/expvar/expvar_test.go18
2 files changed, 26 insertions, 17 deletions
diff --git a/src/expvar/expvar.go b/src/expvar/expvar.go
index 2cb515a678..24c2d6b29a 100644
--- a/src/expvar/expvar.go
+++ b/src/expvar/expvar.go
@@ -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.
diff --git a/src/expvar/expvar_test.go b/src/expvar/expvar_test.go
index 11e6497b96..8bc633e4a9 100644
--- a/src/expvar/expvar_test.go
+++ b/src/expvar/expvar_test.go
@@ -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}',