Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Path
  • Cache Coherency Glossary
  • The Shared Course Model
  • Cache Coherency Revision Sheet
  • Why Coherence Exists8
  • States and Protocols12
  • Transactions12
  • Races and Controller Design8
  • Progress and the Fabric16
  • Ordering and Synchronization12
  • Performance and Scalability12
    • False Sharing
    • Directory Capacity and Sharers
      • Full Bit-Vector Cost
      • Limited Pointers and Coarse Vectors
      • Sparse Directories and Eviction
      • Conservative Metadata Rules
    • Hotspots and Placement
  • Real Protocols12
  • SoC Integration12
  • Power, Clocking and Reliability12
  • Verification12
  • Debug and Bring-up12
  • Interview and Design Review17
  • Capstone: A Coherent Model Lab5
Loading lesson

‹Directory Capacity and Sharers
  1. Topics
  2. Cache Coherency
  3. Performance and Scalability
  4. Directory Capacity and Sharers
  5. Full Bit-Vector Cost

Part 7 · Performance and Scalability · All levels

Full Bit-Vector Cost

Compare full, limited-pointer and coarse entries with explicit fields and find where each one wins.

How many bits are we actually comparing?

Baseline: the pilot entry is 2 state bits (U/S/exclusive) plus one presence bit per cache, 4 bits for C0/C1 and 66 bits for 64 caches, tags and ECC excluded.

Now define two illustrative alternatives rather than claiming universal formats. A four-pointer entry uses 2 state bits, four core-id fields, one valid bit per pointer and one overflow bit (the Dir_i B scheme of the next lesson). A groups-of-eight coarse entry has one bit per group of 8 caches, 2 state bits and a separate exact exclusive-holder id, because a group bit cannot identify that holder. Both describe MESI coverage, not the extra dirty-responsible O tracking needed for MOESI.

Caches N

Full: 2 + N

Four pointers: 2 + 4*(id + 1) + 1

Groups of eight: 2 + N/8 + id

Full as % of 512 data bits

16 (id 4 bits)

18

23

8

3.5%

32 (id 5 bits)

34

27

11

6.6%

64 (id 6 bits), pilot

66

31

16

12.9%

128 (id 7 bits)

130

35

25

25.4%

256 (id 8 bits)

258

39

42

50.4%

1024 (id 10 bits)

1026

47

140

200.4%

Two crossovers follow from these formulas. Four pointers beat the full vector from 26 caches (so from 32 in the table; at 16 they cost 23 bits against 18). The groups-of-eight format grows as N/8 while four pointers grow only with log2 N, so it exceeds four pointers from 233 caches (256 in the table). At 1024 caches a full vector is twice the size of the 512-bit line it tracks.

example.py
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
def formats(n, pointers=4, group=8):
    assert n >= 2 and pointers >= 1 and group >= 1
    ident = (n - 1).bit_length()
    full = 2 + n
    limited = 2 + pointers * (ident + 1) + 1
    coarse = 2 + (n + group - 1) // group + ident
    return full, limited, coarse
assert formats(2)[0] == 4 and formats(64) == (66, 31, 16)  # pilot baseline
table = {16: (18, 23, 8), 32: (34, 27, 11), 128: (130, 35, 25),
         256: (258, 39, 42), 1024: (1026, 47, 140)}
for n, row in table.items():
    assert formats(n) == row
pct = {n: round(100 * formats(n)[0] / 512, 1) for n in (256, 1024)}
assert pct == {256: 50.4, 1024: 200.4}
# Crossovers: four pointers beat the full vector only from 26 caches,
# and the groups-of-eight format exceeds four pointers from 233 caches.
first = min(n for n in range(2, 2048) if formats(n)[1] < formats(n)[0])
assert first == 26 and formats(16)[1] > formats(16)[0]
over = min(n for n in range(2, 2048) if formats(n)[2] > formats(n)[1])
assert over == 233 and formats(128)[2] < formats(128)[1]
# Small-N countercase: even one pointer costs more than the full vector.
full, limited, coarse = formats(2, pointers=1)
assert (full, limited) == (4, 5) and limited > full
lines = (1024 * 1024) // 64  # 1 MiB of memory, one full-map entry per line
assert lines * formats(64)[0] // 8 == 132 * 1024
print("PASS: storage table, crossovers and small-N countercase")
Storage accounting includes all chosen fields, allocated entries and separately identified implementation overheads.
An entry-size comparison is a defined subtotal, not a physical SRAM estimate.

Example total: a full-map directory for 1 MiB of memory keeps one entry per memory line and needs no tag, so 16,384 lines times 66 bits gives 132 KiB for 64 caches. A sparse directory instead tracks cached capacity: sized for 1 MiB of private-cache lines it has the same 16,384 entries, but each also needs an address tag, and its size no longer grows with memory. Physical SRAM rounding, ECC and pending buffers are further terms in both cases.

Common pitfall

Comparing N presence bits with a pointer format that omits valid, overflow or exact exclusive-holder bits, then calling the result complete.

Interview

State the field layout before the arithmetic. Give the two-cache counterexample (one pointer: 5 bits against 4) to the claim that limited pointers always save storage, then the 26-cache crossover.

Check yourself Why is the coarse vector given an exact holder-id field?

In the selected format, a set group bit names up to eight possible cores. An exclusive entry must name exactly one holder so that a GetS can be forwarded to it, so this comparison budgets the exact id.

Related topics

  • Shared course model

  • Original 4/66-bit calculation

Previous

78 / 167

Next: Limited Pointers and Coarse Vectors

Up next

Up nextLimited Pointers and Coarse Vectors

Sign in to save progress

Practice this lessonReport an error

See also

  • Sparse Directories and Eviction
  • Conservative Metadata Rules