Skip to content

Commit 17c6e90

Browse files
authored
compare atomic and mutex performance for incrementing/storing one variable (grpc#1757)
1 parent 65c901e commit 17c6e90

File tree

1 file changed

+142
-1
lines changed

1 file changed

+142
-1
lines changed

benchmark/primitives/primitives_test.go

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// +build go1.7
2+
13
/*
24
*
35
* Copyright 2017 gRPC authors.
@@ -21,9 +23,12 @@
2123
package primitives_test
2224

2325
import (
26+
"fmt"
2427
"sync"
2528
"sync/atomic"
2629
"testing"
30+
"time"
31+
"unsafe"
2732
)
2833

2934
func BenchmarkSelectClosed(b *testing.B) {
@@ -76,7 +81,7 @@ func BenchmarkAtomicBool(b *testing.B) {
7681
}
7782
}
7883

79-
func BenchmarkAtomicValue(b *testing.B) {
84+
func BenchmarkAtomicValueLoad(b *testing.B) {
8085
c := atomic.Value{}
8186
c.Store(0)
8287
x := 0
@@ -92,6 +97,16 @@ func BenchmarkAtomicValue(b *testing.B) {
9297
}
9398
}
9499

100+
func BenchmarkAtomicValueStore(b *testing.B) {
101+
c := atomic.Value{}
102+
v := 123
103+
b.ResetTimer()
104+
for i := 0; i < b.N; i++ {
105+
c.Store(v)
106+
}
107+
b.StopTimer()
108+
}
109+
95110
func BenchmarkMutex(b *testing.B) {
96111
c := sync.Mutex{}
97112
x := 0
@@ -188,6 +203,132 @@ func BenchmarkMutexWithoutDefer(b *testing.B) {
188203
}
189204
}
190205

206+
func BenchmarkAtomicAddInt64(b *testing.B) {
207+
var c int64
208+
b.ResetTimer()
209+
for i := 0; i < b.N; i++ {
210+
atomic.AddInt64(&c, 1)
211+
}
212+
b.StopTimer()
213+
if c != int64(b.N) {
214+
b.Fatal("error")
215+
}
216+
}
217+
218+
func BenchmarkAtomicTimeValueStore(b *testing.B) {
219+
var c atomic.Value
220+
t := time.Now()
221+
b.ResetTimer()
222+
for i := 0; i < b.N; i++ {
223+
c.Store(t)
224+
}
225+
b.StopTimer()
226+
}
227+
228+
func BenchmarkAtomic16BValueStore(b *testing.B) {
229+
var c atomic.Value
230+
t := struct {
231+
a int64
232+
b int64
233+
}{
234+
123, 123,
235+
}
236+
b.ResetTimer()
237+
for i := 0; i < b.N; i++ {
238+
c.Store(t)
239+
}
240+
b.StopTimer()
241+
}
242+
243+
func BenchmarkAtomic32BValueStore(b *testing.B) {
244+
var c atomic.Value
245+
t := struct {
246+
a int64
247+
b int64
248+
c int64
249+
d int64
250+
}{
251+
123, 123, 123, 123,
252+
}
253+
b.ResetTimer()
254+
for i := 0; i < b.N; i++ {
255+
c.Store(t)
256+
}
257+
b.StopTimer()
258+
}
259+
260+
func BenchmarkAtomicPointerStore(b *testing.B) {
261+
t := 123
262+
var up unsafe.Pointer
263+
b.ResetTimer()
264+
for i := 0; i < b.N; i++ {
265+
atomic.StorePointer(&up, unsafe.Pointer(&t))
266+
}
267+
b.StopTimer()
268+
}
269+
270+
func BenchmarkAtomicTimePointerStore(b *testing.B) {
271+
t := time.Now()
272+
var up unsafe.Pointer
273+
b.ResetTimer()
274+
for i := 0; i < b.N; i++ {
275+
atomic.StorePointer(&up, unsafe.Pointer(&t))
276+
}
277+
b.StopTimer()
278+
}
279+
280+
func BenchmarkValueStoreWithContention(b *testing.B) {
281+
t := 123
282+
for _, n := range []int{10, 100, 1000, 10000, 100000} {
283+
b.Run(fmt.Sprintf("Atomic/%v", n), func(b *testing.B) {
284+
var wg sync.WaitGroup
285+
var c atomic.Value
286+
for i := 0; i < n; i++ {
287+
wg.Add(1)
288+
go func() {
289+
for j := 0; j < b.N; j++ {
290+
c.Store(t)
291+
}
292+
wg.Done()
293+
}()
294+
}
295+
wg.Wait()
296+
})
297+
b.Run(fmt.Sprintf("AtomicStorePointer/%v", n), func(b *testing.B) {
298+
var wg sync.WaitGroup
299+
var up unsafe.Pointer
300+
for i := 0; i < n; i++ {
301+
wg.Add(1)
302+
go func() {
303+
for j := 0; j < b.N; j++ {
304+
atomic.StorePointer(&up, unsafe.Pointer(&t))
305+
}
306+
wg.Done()
307+
}()
308+
}
309+
wg.Wait()
310+
})
311+
b.Run(fmt.Sprintf("Mutex/%v", n), func(b *testing.B) {
312+
var wg sync.WaitGroup
313+
var c int
314+
mu := sync.Mutex{}
315+
for i := 0; i < n; i++ {
316+
wg.Add(1)
317+
go func() {
318+
for j := 0; j < b.N; j++ {
319+
mu.Lock()
320+
c = t
321+
mu.Unlock()
322+
}
323+
wg.Done()
324+
}()
325+
}
326+
_ = c
327+
wg.Wait()
328+
})
329+
}
330+
}
331+
191332
type myFooer struct{}
192333

193334
func (myFooer) Foo() {}

0 commit comments

Comments
 (0)