What the machine does

Two probes are two misses

Cuckoo hashing's lookup reads at most two slots, and at a load of 0.45 it reads 1.27 on average where linear probing reads 1.39. Replayed through a cache, it misses 1.18 times a lookup where linear probing misses 0.98. The table that wins the count the analysis uses loses the count the machine charges, because two slots in unrelated places are two cache lines, and a run of adjacent slots is usually one.

Every hash table is analysed in probes. Linear probing’s cost is the expected length of the run of occupied slots a lookup walks; chaining’s is the expected length of a chain; cuckoo hashing’s is at most two, which is its whole appeal. An insertion that can fail and more hashes or wider buckets measured what cuckoo hashing pays for that bound — a construction that fails past a threshold — and took the bound itself as the prize.

A probe is an entry read. On a real machine an entry read costs almost nothing when the entry is already in cache and a great deal when it is not, so the quantity a lookup’s time actually tracks is the number of cache misses it causes, and a probe count predicts that only if every probe is equally likely to miss. This page measures both counts for three tables holding the same keys, to find out whether they are.

Probes per insertion against load factor, table of 8,192The line is Knuth's closed form for linear probing, integrated over the fill; the points are a table actually filled and counted. They agree to within 2.3% everywhere. At a load factor of 0.5 an insertion averages 1.49 probes; at 0.9 it averages 5.39. The formula that matters for insertion is the unsuccessful-search one, ½(1 + 1/(1−α)²), and using the successful-search form instead is an error that hides at low load and is glaring at high load.1234560.000.250.500.75formulameasuredload factor αprobes per insertion8,192 slots, mean of 8 fills, seeds stated in lib/structures.jstwo routes agree to 2.3%
Fig. 1 The analysis this starts from: linear probing’s expected probes per insertion against load, Knuth’s closed form as the line and a filled table of 8,192 slots as points, agreeing to within 2.3%. An insertion averages 1.49 probes at a load of 0.5 and 5.39 at 0.9. Every number on this plate is a count of entries read, and none of them says where those entries are.

Three tables and two counts

The three tables are the standard ones, each holding keys at a stated load in a table of 8,192 slots.

  • Linear probing. One array of slots. A key goes to its hash’s slot or, if that is taken, the next free slot after it. A lookup starts at the hash’s slot and walks forward until it finds the key.
  • Chaining. An array of bucket heads, each pointing to a list of entries allocated separately. A lookup reads the head and follows pointers through the list.
  • Cuckoo hashing. Two arrays, each key in one of two slots — one per array, chosen by two hashes. A lookup reads the first slot and, if the key is not there, the second.

Every key in each table is looked up once, and every entry read is recorded as an address, then replayed through a cache model: fully associative, 64 lines of 8 slots, least-recently-used. For a chained table the bucket heads occupy the table’s addresses and the list nodes occupy addresses after it, in allocation order. Two numbers are reported per lookup: entries read, which is the probe count, and misses, which is the count of reads that had to fetch a line.

Entries read: cuckoo wins, as advertised

At a load of 0.45, cuckoo reads 1.27 entries and misses 1.18; linear probing reads 1.39 and misses 0.98A table of 8,192 slots filled to each load and every key looked up once, the reads replayed through a cache of 64 lines of 8 slots. Linear probing: 1.06 read, 0.93 missed and at most 2 lines at 0.1; 1.14 read, 0.94 missed and at most 2 lines at 0.2; 1.22 read, 0.96 missed and at most 2 lines at 0.3; 1.32 read, 0.97 missed and at most 3 lines at 0.4; 1.39 read, 0.98 missed and at most 3 lines at 0.45; 1.50 read, 0.99 missed and at most 3 lines at 0.5; 1.80 read, 1.02 missed and at most 4 lines at 0.6; 2.24 read, 1.08 missed and at most 8 lines at 0.7; 3.03 read, 1.17 missed and at most 15 lines at 0.8; 5.20 read, 1.43 missed and at most 45 lines at 0.9. Chained: 2.05 read, 1.88 missed and at most 4 lines at 0.1; 2.11 read, 2.00 missed and at most 5 lines at 0.2; 2.15 read, 2.07 missed and at most 5 lines at 0.3; 2.20 read, 2.13 missed and at most 5 lines at 0.4; 2.22 read, 2.16 missed and at most 5 lines at 0.45; 2.26 read, 2.19 missed and at most 6 lines at 0.5; 2.32 read, 2.26 missed and at most 7 lines at 0.6; 2.37 read, 2.31 missed and at most 7 lines at 0.7; 2.42 read, 2.36 missed and at most 8 lines at 0.8; 2.47 read, 2.42 missed and at most 8 lines at 0.9. Cuckoo, two tables: 1.05 read, 0.97 missed and at most 2 lines at 0.1; 1.12 read, 1.04 missed and at most 2 lines at 0.2; 1.17 read, 1.11 missed and at most 2 lines at 0.3; 1.23 read, 1.15 missed and at most 2 lines at 0.4; 1.27 read, 1.18 missed and at most 2 lines at 0.45. Cuckoo, two tables cannot be built past 0.45.linear probingchainedcuckoo, two tables0240.10.20.30.40.50.60.70.80.9load factorentries read per lookup8,192 slots, 64 cache lines of 8a probe is an entry read; a miss is a line fetched
Fig. 2 Entries read per successful lookup against load, for the three tables on 8,192 slots. Linear probing reads 1.06 at a load of 0.1, 1.39 at 0.45 and 5.20 at 0.9. Chaining reads between 2.05 and 2.47 across the range, one for the head and the rest along the chain. Cuckoo hashing reads 1.05 at 0.1 and 1.27 at 0.45, and cannot be constructed past 0.45 on this table.

In the analysis’s currency the ranking is clear. Cuckoo hashing reads the fewest entries at every load where it exists — 1.27 at 0.45, against linear probing’s 1.39 — because at low loads most of its keys are found in the first slot and the rest in the second, and nothing ever makes it read a third. Linear probing is close at low loads and runs away as the table fills. Chaining pays a nearly constant two, since every lookup reads a head and at least one node.

This is the plate that justifies cuckoo hashing, and it is correct.

It is also worth noticing how small the differences on it are at the loads where all three tables run. Between loads of 0.1 and 0.45, linear probing and cuckoo hashing are within ten per cent of each other throughout. An analysis in probes would say that below half full the choice between them is a matter of taste. The next plate says otherwise, and the way it says so is the argument of the page.

Misses: cuckoo loses

At a load of 0.45, cuckoo reads 1.27 entries and misses 1.18; linear probing reads 1.39 and misses 0.98A table of 8,192 slots filled to each load and every key looked up once, the reads replayed through a cache of 64 lines of 8 slots. Linear probing: 1.06 read, 0.93 missed and at most 2 lines at 0.1; 1.14 read, 0.94 missed and at most 2 lines at 0.2; 1.22 read, 0.96 missed and at most 2 lines at 0.3; 1.32 read, 0.97 missed and at most 3 lines at 0.4; 1.39 read, 0.98 missed and at most 3 lines at 0.45; 1.50 read, 0.99 missed and at most 3 lines at 0.5; 1.80 read, 1.02 missed and at most 4 lines at 0.6; 2.24 read, 1.08 missed and at most 8 lines at 0.7; 3.03 read, 1.17 missed and at most 15 lines at 0.8; 5.20 read, 1.43 missed and at most 45 lines at 0.9. Chained: 2.05 read, 1.88 missed and at most 4 lines at 0.1; 2.11 read, 2.00 missed and at most 5 lines at 0.2; 2.15 read, 2.07 missed and at most 5 lines at 0.3; 2.20 read, 2.13 missed and at most 5 lines at 0.4; 2.22 read, 2.16 missed and at most 5 lines at 0.45; 2.26 read, 2.19 missed and at most 6 lines at 0.5; 2.32 read, 2.26 missed and at most 7 lines at 0.6; 2.37 read, 2.31 missed and at most 7 lines at 0.7; 2.42 read, 2.36 missed and at most 8 lines at 0.8; 2.47 read, 2.42 missed and at most 8 lines at 0.9. Cuckoo, two tables: 1.05 read, 0.97 missed and at most 2 lines at 0.1; 1.12 read, 1.04 missed and at most 2 lines at 0.2; 1.17 read, 1.11 missed and at most 2 lines at 0.3; 1.23 read, 1.15 missed and at most 2 lines at 0.4; 1.27 read, 1.18 missed and at most 2 lines at 0.45. Cuckoo, two tables cannot be built past 0.45.linear probingchainedcuckoo, two tables0120.10.20.30.40.50.60.70.80.9load factorcache misses per lookup8,192 slots, 64 cache lines of 8a probe is an entry read; a miss is a line fetched
Fig. 3 Cache misses per successful lookup against load, for the same tables, through a cache of 64 lines of 8 slots. Linear probing misses 0.93 at 0.1, 0.98 at 0.45 and 1.43 at 0.9. Chaining misses between 1.88 and 2.42. Cuckoo hashing misses 0.97 at 0.1 and 1.18 at 0.45 — more than linear probing at every load it reaches.

In the machine’s currency the first two places swap. At a load of 0.45 — the highest this cuckoo table reaches — cuckoo hashing misses 1.18 times per lookup and linear probing 0.98. At every load both can run, cuckoo misses more, and the gap grows with load: 4% more at 0.1, 20% more at 0.45.

The mechanism is the one in the title. A cuckoo lookup that has to read its second slot reads a slot chosen by an independent hash in a different array, and that slot is on a different cache line from the first with near certainty. So every second probe is a second miss. As the load rises, more keys live in their second slot, more lookups make the second probe, and the misses climb towards two probes’ worth.

A linear-probing lookup that walks past its first slot reads the next slot. With eight slots to a cache line, the next slot is on the same line seven times in eight, so a run of two or three probes is usually one miss. Linear probing’s extra probes are nearly free; cuckoo hashing’s are full price.

The arithmetic can be done without the simulation, and doing it confirms the plate rather than replacing it. Suppose a lookup starts at a random slot and the slot’s line is not in cache — the typical case for a table much larger than its cache, since each lookup lands somewhere unrelated to the last. Every lookup then pays one miss for its first probe. A linear-probing lookup that makes pp probes crosses into a new line with probability about (p1)/8(p-1)/8, since each step forward leaves the line one time in eight. At a load of 0.45 with 1.39 probes, that is about 1+0.39/81.051 + 0.39/8 \approx 1.05 misses. A cuckoo lookup pays one miss for its first probe and, whenever it needs its second, another; at 0.45 with 1.27 probes that is about 1+0.27=1.271 + 0.27 = 1.27 misses.

The simulation reports 0.98 and 1.18, somewhat lower than both estimates because some first probes land on a line an earlier lookup left in the cache. The difference the arithmetic predicts — about 0.22 — is the difference the simulation measures, 0.20. So the whole effect is the second term: linear probing divides its extra probes by the number of slots on a line, and cuckoo hashing does not.

Chaining is worst in both currencies and for the same reason in both: a list node is a separate allocation, reached by a pointer, and a pointer can point anywhere. Every node on a chain is a miss unless it happens to share a line with the head, and it almost never does.

Chaining’s numbers at low load make the point most sharply. At a load of 0.1 almost every chain holds one entry, so a successful lookup reads the head and one node — 2.05 entries — and misses 1.88 times. The head and the node are two separate places in memory whatever the chain’s length, so chaining starts at nearly two misses a lookup when its analysis says it is doing almost nothing, and its misses barely move as the load rises because the second miss was never about length. Its probe count looks like a structure that is nearly free at low load; its miss count looks like a structure with a fixed toll of one pointer chase per lookup, which is what it is.

The two counts side by side

At a load of 0.45, cuckoo reads 1.27 entries and misses 1.18; linear probing reads 1.39 and misses 0.98A table of 8,192 slots filled to each load and every key looked up once, the reads replayed through a cache of 64 lines of 8 slots. Linear probing: 1.06 read, 0.93 missed and at most 2 lines at 0.1; 1.14 read, 0.94 missed and at most 2 lines at 0.2; 1.22 read, 0.96 missed and at most 2 lines at 0.3; 1.32 read, 0.97 missed and at most 3 lines at 0.4; 1.39 read, 0.98 missed and at most 3 lines at 0.45; 1.50 read, 0.99 missed and at most 3 lines at 0.5; 1.80 read, 1.02 missed and at most 4 lines at 0.6; 2.24 read, 1.08 missed and at most 8 lines at 0.7; 3.03 read, 1.17 missed and at most 15 lines at 0.8; 5.20 read, 1.43 missed and at most 45 lines at 0.9. Chained: 2.05 read, 1.88 missed and at most 4 lines at 0.1; 2.11 read, 2.00 missed and at most 5 lines at 0.2; 2.15 read, 2.07 missed and at most 5 lines at 0.3; 2.20 read, 2.13 missed and at most 5 lines at 0.4; 2.22 read, 2.16 missed and at most 5 lines at 0.45; 2.26 read, 2.19 missed and at most 6 lines at 0.5; 2.32 read, 2.26 missed and at most 7 lines at 0.6; 2.37 read, 2.31 missed and at most 7 lines at 0.7; 2.42 read, 2.36 missed and at most 8 lines at 0.8; 2.47 read, 2.42 missed and at most 8 lines at 0.9. Cuckoo, two tables: 1.05 read, 0.97 missed and at most 2 lines at 0.1; 1.12 read, 1.04 missed and at most 2 lines at 0.2; 1.17 read, 1.11 missed and at most 2 lines at 0.3; 1.23 read, 1.15 missed and at most 2 lines at 0.4; 1.27 read, 1.18 missed and at most 2 lines at 0.45. Cuckoo, two tables cannot be built past 0.45.linear probingchainedcuckoo, two tables0240.10.20.30.40.50.60.70.80.9load factorentries read per lookup0120.10.20.30.40.50.60.70.80.9load factorcache misses per lookup8,192 slots, 64 cache lines of 8a probe is an entry read; a miss is a line fetched
Fig. 4 Both counts on one plate: entries read on the left and misses on the right, for linear probing, chaining and cuckoo hashing across loads from 0.1 to 0.9. On the left cuckoo is the lowest line wherever it exists; on the right linear probing is. At a load of 0.45 cuckoo reads 1.27 entries and misses 1.18 times; linear probing reads 1.39 and misses 0.98.

Side by side the two panels make the inversion obvious. The ordering on the left is the one in every textbook; the ordering on the right is the one a profiler reports. Two counts disagree is this collection’s theme for exactly this, and where an algorithm looks is its general form: an access pattern is priced by its locality, and a count of accesses assigns every pattern the same price.

It is worth noticing what the right-hand panel does to linear probing’s reputation as well. Its probe count at a load of 0.9 is 5.20, the familiar runaway that makes the method sound fragile at high load. Its miss count at 0.9 is 1.43. The runaway is a runaway in entries read, most of which are on lines the lookup has already fetched, and in misses it is mild. The probe formula nobody checks measured how closely the formula tracks a real table; this plate measures how little the formula’s quantity tracks what the table costs on a machine with a cache.

Smaller lines

At a load of 0.45, cuckoo reads 1.27 entries and misses 1.22; linear probing reads 1.39 and misses 1.05A table of 8,192 slots filled to each load and every key looked up once, the reads replayed through a cache of 64 lines of 4 slots. Linear probing: 1.06 read, 0.97 missed and at most 2 lines at 0.1; 1.14 read, 0.99 missed and at most 2 lines at 0.2; 1.22 read, 1.02 missed and at most 3 lines at 0.3; 1.32 read, 1.04 missed and at most 4 lines at 0.4; 1.39 read, 1.05 missed and at most 4 lines at 0.45; 1.50 read, 1.08 missed and at most 5 lines at 0.5; 1.80 read, 1.15 missed and at most 7 lines at 0.6; 2.24 read, 1.27 missed and at most 15 lines at 0.7; 3.03 read, 1.45 missed and at most 29 lines at 0.8; 5.20 read, 1.99 missed and at most 89 lines at 0.9. Chained: 2.05 read, 1.98 missed and at most 4 lines at 0.1; 2.11 read, 2.07 missed and at most 5 lines at 0.2; 2.15 read, 2.12 missed and at most 5 lines at 0.3; 2.20 read, 2.17 missed and at most 5 lines at 0.4; 2.22 read, 2.20 missed and at most 5 lines at 0.45; 2.26 read, 2.23 missed and at most 6 lines at 0.5; 2.32 read, 2.29 missed and at most 7 lines at 0.6; 2.37 read, 2.35 missed and at most 7 lines at 0.7; 2.42 read, 2.39 missed and at most 8 lines at 0.8; 2.47 read, 2.44 missed and at most 8 lines at 0.9. Cuckoo, two tables: 1.05 read, 1.01 missed and at most 2 lines at 0.1; 1.12 read, 1.08 missed and at most 2 lines at 0.2; 1.17 read, 1.15 missed and at most 2 lines at 0.3; 1.23 read, 1.19 missed and at most 2 lines at 0.4; 1.27 read, 1.22 missed and at most 2 lines at 0.45. Cuckoo, two tables cannot be built past 0.45.linear probingchainedcuckoo, two tables0240.10.20.30.40.50.60.70.80.9load factorentries read per lookup0120.10.20.30.40.50.60.70.80.9load factorcache misses per lookup8,192 slots, 64 cache lines of 4a probe is an entry read; a miss is a line fetched
Fig. 5 The same tables with cache lines of 4 slots instead of 8. Linear probing now misses 0.97 at 0.1, 1.05 at 0.45 and 1.99 at 0.9; cuckoo hashing misses 1.01 at 0.1 and 1.22 at 0.45; chaining between 1.98 and 2.44. With half as many slots to a line, linear probing’s runs cross line boundaries twice as often and its advantage narrows.

The account predicts that linear probing’s advantage depends on how many slots share a line, and halving the line size tests that. With four slots to a line, a run of probes crosses into a new line twice as often, so linear probing’s misses rise — most visibly at high load, where the runs are long, 1.43 becoming 1.99 at 0.9. Cuckoo hashing’s misses barely move, because its two probes were already on different lines and making lines smaller cannot separate them further.

At a load of 0.45 the gap between the two narrows from 0.20 misses to 0.17. It does not close: even with four slots to a line, most short runs stay within one. Real cache lines hold more entries than four for any table of pointers or small integers, so the eight-slot plate is closer to the ordinary case.

A cache that holds the whole table

At a load of 0.45, cuckoo reads 1.27 entries and misses 0.27; linear probing reads 1.39 and misses 0.27A table of 8,192 slots filled to each load and every key looked up once, the reads replayed through a cache of 1024 lines of 8 slots. Linear probing: 1.06 read, 0.67 missed and at most 2 lines at 0.1; 1.14 read, 0.49 missed and at most 2 lines at 0.2; 1.22 read, 0.38 missed and at most 2 lines at 0.3; 1.32 read, 0.30 missed and at most 3 lines at 0.4; 1.39 read, 0.27 missed and at most 3 lines at 0.45; 1.50 read, 0.24 missed and at most 3 lines at 0.5; 1.80 read, 0.21 missed and at most 4 lines at 0.6; 2.24 read, 0.18 missed and at most 8 lines at 0.7; 3.03 read, 0.16 missed and at most 15 lines at 0.8; 5.20 read, 0.14 missed and at most 45 lines at 0.9. Chained: 2.05 read, 0.92 missed and at most 4 lines at 0.1; 2.11 read, 0.80 missed and at most 5 lines at 0.2; 2.15 read, 0.98 missed and at most 5 lines at 0.3; 2.20 read, 1.12 missed and at most 5 lines at 0.4; 2.22 read, 1.19 missed and at most 5 lines at 0.45; 2.26 read, 1.26 missed and at most 6 lines at 0.5; 2.32 read, 1.38 missed and at most 7 lines at 0.6; 2.37 read, 1.48 missed and at most 7 lines at 0.7; 2.42 read, 1.56 missed and at most 8 lines at 0.8; 2.47 read, 1.64 missed and at most 8 lines at 0.9. Cuckoo, two tables: 1.05 read, 0.69 missed and at most 2 lines at 0.1; 1.12 read, 0.52 missed and at most 2 lines at 0.2; 1.17 read, 0.39 missed and at most 2 lines at 0.3; 1.23 read, 0.31 missed and at most 2 lines at 0.4; 1.27 read, 0.27 missed and at most 2 lines at 0.45. Cuckoo, two tables cannot be built past 0.45.linear probingchainedcuckoo, two tables0240.10.20.30.40.50.60.70.80.9load factorentries read per lookup00.511.50.10.20.30.40.50.60.70.80.9load factorcache misses per lookup8,192 slots, 1024 cache lines of 8a probe is an entry read; a miss is a line fetched
Fig. 6 The same tables with a cache of 1,024 lines — 8,192 slots, enough to hold the whole table. Linear probing’s misses fall with load, from 0.67 at 0.1 to 0.14 at 0.9; cuckoo hashing’s from 0.69 to 0.27 at 0.45. Chaining’s rise, from 0.92 to 1.64, because its list nodes live outside the table and there are more of them as the load grows.

With a cache large enough to hold the whole table, the picture changes character. For linear probing and cuckoo hashing every miss is now a first touch of a line, and every line is fetched at most once in the whole run of lookups. A fuller table means more lookups sharing the same lines, so the misses per lookup fall as the load rises — linear probing to 0.14 at 0.9. The two tables are nearly equal at 0.45, 0.27 each, since each touches every line of the table once and the number of lookups is the same.

Chaining alone gets worse, and the reason is the one the design of chaining cannot escape. Its nodes are allocated outside the table, one per key, so the number of lines they occupy grows with the number of keys, and the cache that holds the table does not hold them. At a load of 0.9 chaining misses 1.64 times per lookup where linear probing misses 0.14 — more than eleven times as often, in a regime where the cache is supposedly large enough. A bucket that becomes a tree measured a library that converts long chains to trees to bound their length; that bounds the probes and leaves every node a pointer away.

This last plate is also a reminder about where a measurement’s regime comes from. On a cache of 64 lines, every table misses about once per lookup at least, because lookups land on lines the cache does not hold. On a cache that holds the table, most lookups miss not at all, and the question becomes whether a table’s entries live inside the region the cache holds. The cliff where the data stops fitting measures the step between those two regimes for arrays; a hash table has the same step, and the ranking of tables on one side of it is not the ranking on the other. The count is not the time is the general form of the warning, and a probe count is a particularly clean instance of a count whose relation to time changes sign across a cache boundary.

What a table’s designer is choosing

Put together, the plates say what each table is good at in a machine’s terms rather than an analysis’s.

Linear probing has the best locality of the three by a wide margin, because its probes are adjacent. Its weakness in probes at high load is mostly hidden by that locality, and it becomes a real weakness only when lines are small or the load is very high. It gives no worst-case bound: a long run is possible, and an adversary who can choose keys can make one.

Cuckoo hashing has a worst-case bound of two probes, which is a genuine guarantee against adversarial and unlucky keys, and it pays for the guarantee in misses on the common case as well as in a construction threshold. The bound matters most where a tail matters — the probe nobody waits for is this collection’s account of why a table’s worst lookup can matter more than its average — and least in a table serving many lookups whose average sets throughput.

Chaining has the worst locality in every regime, and its advantage — it never fills, and deletion is simple — is paid for in a pointer chase per lookup that no load factor removes.

That summary also says which variant of cuckoo hashing recovers the locality. If each of a key’s two candidate places is a bucket of several slots laid out on one cache line, a lookup reads up to eight slots in two lines — two misses, as before — but the table holds far more keys before its threshold. More hashes or wider buckets measured that shape’s threshold beyond 0.95; its misses per lookup should be about the plain cuckoo table’s two probes’ worth at every load, which is higher than linear probing’s but no longer rises with load, and the construction no longer fails at a half.

What the measurement leaves out

One level of cache and no prefetching. A hardware prefetcher recognises a lookup that walks forward through adjacent slots and fetches ahead, which helps linear probing further; it cannot predict an independent hash, which helps cuckoo hashing not at all. So the gap on these plates is if anything conservative.

Successful lookups only. An unsuccessful lookup in linear probing walks to the end of a run, which is longer than the walk to a present key, and in cuckoo hashing always reads both slots. Both change the counts in cuckoo hashing’s favour by a little and change the misses in linear probing’s favour by less, since the extra probes are adjacent.

Allocation order for chains. The chained table’s nodes are allocated in insertion order, which scatters a bucket’s nodes as widely as any allocator would. An allocator that places nodes near their bucket, or a chained table that stores its first entry in the bucket itself, would move chaining’s misses towards linear probing’s — which is what open-addressing tables already are.

The keys are random. A table’s probes are a property of its keys and its hash, and the relative ordering here is for keys a good hash has made look random.

Lookups in arbitrary order. Every key is looked up once, in insertion order, which for a hashed table is a random order over the slots. A workload that looks up the same few keys repeatedly keeps their lines in cache and makes every table cheap; a workload that looks up keys in an order correlated with their slots — a scan, or a join over sorted keys — rewards linear probing’s locality even more. The plates are for the case with no correlation, which is the case where the tables differ least in their favour and most in their structure.

Where this ladder goes next: a bucket the size of a cache line

The last section predicted a table from two measurements and did not build it. A cuckoo table whose candidates are buckets of four or eight slots, each bucket aligned to one cache line, should read at most two lines per lookup at any load up to its threshold — which for buckets of four is above 0.95 — and should therefore miss at most twice, with no runaway at high load and no failure at a half.

The measurement is the one on this page with a fourth table added, at line sizes of four and eight, across the same loads. The prediction is that it misses more than linear probing at low loads, where linear probing’s runs are one line, and fewer at high loads, where linear probing’s runs cross lines — and that the crossing falls somewhere between 0.8 and 0.9. If it does, the table with the worst locality on this page becomes, with one change to what a slot is, the table with the best worst case and competitive locality, and the choice between the two families stops being a choice between a guarantee and a cache.

What this makes readable

Essays that name this one as a prerequisite.

Named alongside this one

Essays reaching for the same objects. Nobody chose these; they are what the concept index makes visible.

What links here

Every essay whose body links to this one.

The objects this essay names

Each one links to every other essay that touches it.

CacheChained hashingCuckoo hashingHash tableLinear probingLoad factorLocalityMemory layoutMiss rateOperation countPointer chasingWorst case guarantee