Sixty Four Bytes Apart

x86-64, 64-byte cache lines, two cores.

struct Counters {
    std::atomic<long> a;
    std::atomic<long> b;
};
Counters c;

// core 0: for (long i = 0; i < 100'000'000; i++) c.a.fetch_add(1);
// core 1: for (long i = 0; i < 100'000'000; i++) c.b.fetch_add(1);

Both final values are exactly 100,000,000, so the program is correct. It runs roughly 5x slower than the same two loops on counters allocated in separate structs. Which change fixes the slowdown?

A

Take a mutex around each increment so the line is claimed once per critical section

B

Give each counter alignas(64) so a and b occupy different cache lines

C

Switch both fetch_add calls to std::memory_order_relaxed

D

Replace std::atomic<long> with volatile long