-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathex03_false_sharing.go
More file actions
56 lines (49 loc) · 1.91 KB
/
ex03_false_sharing.go
File metadata and controls
56 lines (49 loc) · 1.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
package memorymodel
import (
"sync"
"sync/atomic"
)
// Context: False Sharing (CPU Cache Line Contention)
// You have a high-performance metrics aggregator counting API hits.
// You have 8 worker goroutines, but you give them separate independent
// counters so they don't block each other on a Mutex.
//
// Why this matters: The CPU cache pushes data around in 64-byte chunks (Cache Lines).
// Since `Counter1` and `Counter2` are consecutive `int64`s (8 bytes each),
// they fit into the SAME 64-byte CPU cache line.
// Even though Worker 1 only writes to `Counter1` and Worker 2 only writes to `Counter2`,
// the CPU hardware falsely registers a memory collision and constantly invalidates
// and bounces the exact same cache line back and forth between core L1 caches.
// This plummets multithreaded performance to worse than single-threaded locking!
//
// Requirements:
// 1. Run `go test -bench BenchmarkFalseSharing` to see the baseline speed.
// 2. Add struct padding to `PaddedMetrics`.
// (Hint: Add `_ [56]byte` between the counters so they exceed the 64-byte cache line).
// 3. Rerun the benchmark to witness the massive throughput explosion when cores
// no longer falsely share cache lines.
type NaiveMetrics struct {
Counter1 int64
Counter2 int64
}
// TODO: Fix false sharing by ensuring these counters are physically separated
// in RAM by at least 64 bytes (the size of a standard CPU cache line).
type PaddedMetrics struct {
// BUG: These share the same cache line.
// Insert padding here: `_ [56]byte` (64 bytes - 8 bytes for int64)
Counter1 int64
Counter2 int64
}
// These functions are provided to test the benchmarks.
func UpdateNaive(m *NaiveMetrics, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 10_000_000; i++ {
atomic.AddInt64(&m.Counter1, 1)
}
}
func UpdatePadded(m *PaddedMetrics, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 10_000_000; i++ {
atomic.AddInt64(&m.Counter1, 1)
}
}