Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 95c0d67

Browse files
committed
Further reduce the cost of hash collisions by inspecting an additional nearby entry.
1 parent 34567ec commit 95c0d67

1 file changed

Lines changed: 39 additions & 4 deletions

File tree

Objects/setobject.c

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,11 @@ chaining would be substantial (100% with typical malloc overhead).
6565
The initial probe index is computed as hash mod the table size. Subsequent
6666
probe indices are computed as explained in Objects/dictobject.c.
6767
68-
To improve cache locality, each probe is done in pairs.
69-
After the probe is examined, an adjacent entry is then examined as well.
70-
The likelihood is that an adjacent entry is in the same cache line and
71-
can be examined more cheaply than another probe elsewhere in memory.
68+
To improve cache locality, each probe inspects nearby entries before
69+
moving on to probes elsewhere in memory. Depending on alignment and the
70+
size of a cache line, the nearby entries are cheaper to inspect than
71+
other probes elsewhere in memory. This probe strategy reduces the cost
72+
of hash collisions.
7273
7374
All arithmetic on hash should ignore overflow.
7475
@@ -130,6 +131,26 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
130131
if (entry->key == dummy && freeslot == NULL)
131132
freeslot = entry;
132133

134+
entry = &table[j ^ 2];
135+
if (entry->key == NULL)
136+
break;
137+
if (entry->key == key)
138+
return entry;
139+
if (entry->hash == hash && entry->key != dummy) {
140+
PyObject *startkey = entry->key;
141+
Py_INCREF(startkey);
142+
cmp = PyObject_RichCompareBool(startkey, key, Py_EQ);
143+
Py_DECREF(startkey);
144+
if (cmp < 0)
145+
return NULL;
146+
if (table != so->table || entry->key != startkey)
147+
return set_lookkey(so, key, hash);
148+
if (cmp > 0)
149+
return entry;
150+
}
151+
if (entry->key == dummy && freeslot == NULL)
152+
freeslot = entry;
153+
133154
i = i * 5 + perturb + 1;
134155
j = i & mask;
135156
perturb >>= PERTURB_SHIFT;
@@ -190,6 +211,17 @@ set_lookkey_unicode(PySetObject *so, PyObject *key, Py_hash_t hash)
190211
if (entry->key == dummy && freeslot == NULL)
191212
freeslot = entry;
192213

214+
entry = &table[j ^ 2];
215+
if (entry->key == NULL)
216+
break;
217+
if (entry->key == key
218+
|| (entry->hash == hash
219+
&& entry->key != dummy
220+
&& unicode_eq(entry->key, key)))
221+
return entry;
222+
if (entry->key == dummy && freeslot == NULL)
223+
freeslot = entry;
224+
193225
i = i * 5 + perturb + 1;
194226
j = i & mask;
195227
perturb >>= PERTURB_SHIFT;
@@ -256,6 +288,9 @@ set_insert_clean(PySetObject *so, PyObject *key, Py_hash_t hash)
256288
if (entry->key == NULL)
257289
break;
258290
entry = &table[j ^ 1];
291+
if (entry->key == NULL)
292+
break;
293+
entry = &table[j ^ 2];
259294
if (entry->key == NULL)
260295
break;
261296
i = i * 5 + perturb + 1;

0 commit comments

Comments
 (0)