-
Notifications
You must be signed in to change notification settings - Fork 400
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(pkg/counter): finish making counter atomic (#3276)
Last changes renamed Increment/Decrement to Increase/Decrease. This was reverted after discussions. With this new approach: - Overflow is detected in both cases (and proved by test). - Thread safety is guaranteed by atomic Add/Sub operations. - Unit tests prove all assumptions and thread safety for all cases. - Benchmark tests can be used to test other approaches in the future. - Overflow of a sum of all given arguments isn't detected (avoid overhead). NOTE: The issue is now fully fixed... Originally, the bug was only about reading counter value in parallel to atomic operation (multiple LOAD/STORE simultaneously, and some not protected by atomics). Previous fix, made by commit 1e54ce2, fixed data race but overflow errors could be reported more than once. It also had atomic operations for each given argument (if multiple arguments). This version addresses all concerns.
- Loading branch information
1 parent
8d5237a
commit 0b97409
Showing
15 changed files
with
352 additions
and
192 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package counter | ||
|
||
import "testing" | ||
|
||
// Increment | ||
|
||
func BenchmarkIncrement(b *testing.B) { | ||
c := NewCounter(0) | ||
|
||
for i := 0; i < b.N; i++ { | ||
err := c.Increment() | ||
if err != nil { | ||
b.Fatal(err) | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkIncrementWithValue(b *testing.B) { | ||
c := NewCounter(0) | ||
|
||
for i := 0; i < b.N; i++ { | ||
err := c.Increment(1) | ||
if err != nil { | ||
b.Fatal(err) | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkIncrementWithMultipleValue(b *testing.B) { | ||
c := NewCounter(0) | ||
|
||
for i := 0; i < b.N; i += 3 { | ||
err := c.Increment(1, 1, 1) | ||
if err != nil { | ||
b.Fatal(err) | ||
} | ||
} | ||
|
||
// Note: Looping 1/3 of times in this case | ||
} | ||
|
||
func BenchmarkZeroedIncrementWithValue(b *testing.B) { | ||
c := NewCounter(0) | ||
|
||
for i := 0; i < b.N; i++ { | ||
err := c.Increment(0) | ||
if err != nil { | ||
b.Fatal(err) | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkZeroedIncrementWithMultipleValue(b *testing.B) { | ||
c := NewCounter(0) | ||
|
||
for i := 0; i < b.N; i++ { | ||
err := c.Increment(0, 0, 0) | ||
if err != nil { | ||
b.Fatal(err) | ||
} | ||
} | ||
} | ||
|
||
// Decrement | ||
|
||
func BenchmarkDecrement(b *testing.B) { | ||
c := NewCounter(uint64(b.N)) | ||
|
||
for i := b.N; i > 0; i-- { | ||
err := c.Decrement() | ||
if err != nil { | ||
b.Fatal(err) | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkDecrementWithValue(b *testing.B) { | ||
c := NewCounter(uint64(b.N)) | ||
|
||
for i := b.N; i > 0; i-- { | ||
err := c.Decrement(1) | ||
if err != nil { | ||
b.Fatal(err) | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkDecrementWithMultipleValue(b *testing.B) { | ||
c := NewCounter(uint64(b.N)) | ||
|
||
for i := b.N; i > 3; i -= 3 { | ||
err := c.Decrement(1, 1, 1) | ||
if err != nil { | ||
b.Fatal(err) | ||
} | ||
} | ||
|
||
// Note: Looping 1/3 of times in this case | ||
} | ||
|
||
func BenchmarkZeroedDecrementWithValue(b *testing.B) { | ||
c := NewCounter(uint64(b.N)) | ||
|
||
for i := b.N; i > 0; i-- { | ||
err := c.Decrement(0) | ||
if err != nil { | ||
b.Fatal(err) | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkZeroedDecrementWithMultipleValue(b *testing.B) { | ||
c := NewCounter(uint64(b.N)) | ||
|
||
for i := b.N; i > 0; i-- { | ||
err := c.Decrement(0, 0, 0) | ||
if err != nil { | ||
b.Fatal(err) | ||
} | ||
} | ||
} |
Oops, something went wrong.