Use the same completed-operation schedule: C0 writes, C1 writes, repeat. X starts at 0 uncached. For false sharing add Y=0 at offset 8 in X's line; for separated fields move Y to the next line at offset 64. True sharing instead sends both writes to X. The Python uses byte addresses and eight words per line, preserving the entire current payload on each transfer. It counts messages per line, so a control can show that moving an unrelated field (offset 64, written by C1) does nothing for a truly shared X, and a failing case zeroes the payload on transfer to prove the value check bites.
Count the course's MESI write-only paths: a first GetM from U and its Data grant are two interconnect messages. A change of exclusive holder uses the H-buffered four-hop route, the course default: GetM, Fwd-GetM, Data to H, Data to the requester, four messages. The direct route is three messages (GetM, Fwd-GetM, Data straight to the requester) plus a completion to H: one fewer leg on C1's critical path, but still four messages per transfer in this count. Either way the comparison between layouts is unchanged, because it depends on the number of holder changes. Repeated writes by the current holder are local. Memory reads and local stores are not interconnect messages. There are no reads, evictions or overlapping transactions in this workload. Each operation completes before the next starts, including the course's assumed grant-delivery knowledge.
# Simplified course model: MESI writes only, each GetM completes atomically,
# H's record is the holders dict, updated at once, no transients or races.
from collections import Counter
LINE, WORDS = 64, 8
def run(trace, broken=False):
holders, payloads, expected, per_line = {}, {}, {}, Counter()
for value, (core, address) in enumerate(trace, 1):
line, word = address // LINE, (address % LINE) // 8
if line not in holders:
payloads[line] = [0] * WORDS
per_line[line] += 2 # GetM, Data
elif holders[line] != core:
# Transfer the complete current payload, not stale memory bytes.
payloads[line] = [0] * WORDS if broken else list(payloads[line])
per_line[line] += 4 # GetM, Fwd-GetM, Data to H, Data to C
holders[line] = core
payloads[line][word] = value
expected[address] = value
actual = {a: payloads[a // LINE][(a % LINE) // 8] for a in expected}
assert actual == expected
return sum(per_line.values()), actual, per_line
def alternating(rounds, second_address):
return [(core, 0 if core == 0 else second_address)
for _ in range(rounds) for core in (0, 1)]
for rounds in range(1, 9):
true, _, _ = run(alternating(rounds, 0))
false, fields, _ = run(alternating(rounds, 8))
padded, split, _ = run(alternating(rounds, 64))
assert true == false == 2 + 4 * (2 * rounds - 1)
assert padded == 4 and padded < false
assert fields[0] == split[0] and fields[8] == split[64]
# Control: X stays truly shared while C1 also writes an unrelated
# field at offset 64. Padding elsewhere leaves X's traffic unchanged.
control = [s for _ in range(rounds) for s in ((0, 0), (1, 0), (1, 64))]
_, _, lines = run(control)
assert lines[0] == true and lines[1] == 2
assert run(alternating(8, 0))[0] == run(alternating(8, 8))[0] == 62
assert run(alternating(8, 64))[0] == 4
_, _, lines = run([s for _ in range(8) for s in ((0, 0), (1, 0), (1, 64))])
assert lines[0] == 62
batch = [(0, 0)] * 8 + [(1, 8)] * 8
assert run(batch)[0] == 6
try:
run(alternating(2, 8), broken=True)
except AssertionError:
pass
else:
raise AssertionError("lost neighbouring data was not detected")
print("PASS: separated fields reduce transfers, shared X still contends")Illustrative 8 rounds, 16 stores | Messages | What changed |
|---|---|---|
True sharing, same X | 62 | One cold acquisition, 15 holder changes. |
False sharing, X/Y in one line | 62 | Same holder schedule despite independent fields. |
Separated X/Y lines | 4 | Two cold acquisitions, then local stores. |
Batched X/Y writes in one line | 6 | One cold acquisition and one holder change. |
The test asserts a family of schedule lengths, exact field values, the per-line control and the table's 62, 4 and 6 counts. The 62-versus-4 result is a message count for the stated workload, not a measured speedup. A workload with capacity evictions, readers or shared logical state needs a different accounting experiment.
The expected-field assertions fail when the second writer overwrites its word and loses the first writer's word. Lower traffic would not excuse that value loss.