From 17c6e90cd58d4eef0f6cad2f772bb978b21b163f Mon Sep 17 00:00:00 2001 From: lyuxuan Date: Tue, 2 Jan 2018 10:46:13 -0800 Subject: [PATCH] compare atomic and mutex performance for incrementing/storing one variable (#1757) --- benchmark/primitives/primitives_test.go | 143 +++++++++++++++++++++++- 1 file changed, 142 insertions(+), 1 deletion(-) diff --git a/benchmark/primitives/primitives_test.go b/benchmark/primitives/primitives_test.go index 59355590..9937ae77 100644 --- a/benchmark/primitives/primitives_test.go +++ b/benchmark/primitives/primitives_test.go @@ -1,3 +1,5 @@ +// +build go1.7 + /* * * Copyright 2017 gRPC authors. @@ -21,9 +23,12 @@ package primitives_test import ( + "fmt" "sync" "sync/atomic" "testing" + "time" + "unsafe" ) func BenchmarkSelectClosed(b *testing.B) { @@ -76,7 +81,7 @@ func BenchmarkAtomicBool(b *testing.B) { } } -func BenchmarkAtomicValue(b *testing.B) { +func BenchmarkAtomicValueLoad(b *testing.B) { c := atomic.Value{} c.Store(0) x := 0 @@ -92,6 +97,16 @@ func BenchmarkAtomicValue(b *testing.B) { } } +func BenchmarkAtomicValueStore(b *testing.B) { + c := atomic.Value{} + v := 123 + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Store(v) + } + b.StopTimer() +} + func BenchmarkMutex(b *testing.B) { c := sync.Mutex{} x := 0 @@ -188,6 +203,132 @@ func BenchmarkMutexWithoutDefer(b *testing.B) { } } +func BenchmarkAtomicAddInt64(b *testing.B) { + var c int64 + b.ResetTimer() + for i := 0; i < b.N; i++ { + atomic.AddInt64(&c, 1) + } + b.StopTimer() + if c != int64(b.N) { + b.Fatal("error") + } +} + +func BenchmarkAtomicTimeValueStore(b *testing.B) { + var c atomic.Value + t := time.Now() + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Store(t) + } + b.StopTimer() +} + +func BenchmarkAtomic16BValueStore(b *testing.B) { + var c atomic.Value + t := struct { + a int64 + b int64 + }{ + 123, 123, + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Store(t) + } + b.StopTimer() +} + +func BenchmarkAtomic32BValueStore(b *testing.B) { + var c atomic.Value + t := struct { + a int64 + b int64 + c int64 + d int64 + }{ + 123, 123, 123, 123, + } + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Store(t) + } + b.StopTimer() +} + +func BenchmarkAtomicPointerStore(b *testing.B) { + t := 123 + var up unsafe.Pointer + b.ResetTimer() + for i := 0; i < b.N; i++ { + atomic.StorePointer(&up, unsafe.Pointer(&t)) + } + b.StopTimer() +} + +func BenchmarkAtomicTimePointerStore(b *testing.B) { + t := time.Now() + var up unsafe.Pointer + b.ResetTimer() + for i := 0; i < b.N; i++ { + atomic.StorePointer(&up, unsafe.Pointer(&t)) + } + b.StopTimer() +} + +func BenchmarkValueStoreWithContention(b *testing.B) { + t := 123 + for _, n := range []int{10, 100, 1000, 10000, 100000} { + b.Run(fmt.Sprintf("Atomic/%v", n), func(b *testing.B) { + var wg sync.WaitGroup + var c atomic.Value + for i := 0; i < n; i++ { + wg.Add(1) + go func() { + for j := 0; j < b.N; j++ { + c.Store(t) + } + wg.Done() + }() + } + wg.Wait() + }) + b.Run(fmt.Sprintf("AtomicStorePointer/%v", n), func(b *testing.B) { + var wg sync.WaitGroup + var up unsafe.Pointer + for i := 0; i < n; i++ { + wg.Add(1) + go func() { + for j := 0; j < b.N; j++ { + atomic.StorePointer(&up, unsafe.Pointer(&t)) + } + wg.Done() + }() + } + wg.Wait() + }) + b.Run(fmt.Sprintf("Mutex/%v", n), func(b *testing.B) { + var wg sync.WaitGroup + var c int + mu := sync.Mutex{} + for i := 0; i < n; i++ { + wg.Add(1) + go func() { + for j := 0; j < b.N; j++ { + mu.Lock() + c = t + mu.Unlock() + } + wg.Done() + }() + } + _ = c + wg.Wait() + }) + } +} + type myFooer struct{} func (myFooer) Foo() {}