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

Skip to content

Commit 8408dc5

Browse files
committed
Issue 18771: Make it possible to set the number linear probes at compile-time.
1 parent e6d35db commit 8408dc5

2 files changed

Lines changed: 28 additions & 7 deletions

File tree

Doc/whatsnew/3.4.rst

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,15 @@ Major performance enhancements have been added:
444444
* The UTF-32 decoder is now 3x to 4x faster.
445445

446446
* The cost of hash collisions for sets is now reduced. Each hash table
447-
probe now checks a second key/hash pair for each cache line retrieved.
448-
This exploits cache locality to make collision resolution less expensive.
447+
probe now checks a series of consecutive, adjacent key/hash pairs before
448+
continuing to make random probes through the hash table. This exploits
449+
cache locality to make collision resolution less expensive.
450+
451+
The collision resolution scheme can be described as a hybrid of linear
452+
probing and open addressing. The number of additional linear probes
453+
defaults to nine. This can be changed at compile-time by defining
454+
LINEAR_PROBES to be any value. Set LINEAR_PROBES=0 to turn-off
455+
linear probing entirely.
449456

450457
(Contributed by Raymond Hettinger in :issue"`18771`.)
451458

Objects/setobject.c

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,9 @@ PyObject *_PySet_Dummy = dummy;
4444
/* ======= Begin logic for probing the hash table ========================= */
4545

4646
/* This should be >= PySet_MINSIZE - 1 */
47+
#ifndef LINEAR_PROBES
4748
#define LINEAR_PROBES 9
49+
#endif
4850

4951
/* This must be >= 1 */
5052
#define PERTURB_SHIFT 5
@@ -55,12 +57,14 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
5557
setentry *table = so->table;
5658
setentry *freeslot = NULL;
5759
setentry *entry;
58-
setentry *limit;
5960
size_t perturb = hash;
6061
size_t mask = so->mask;
6162
size_t i = (size_t)hash; /* Unsigned for defined overflow behavior. */
62-
size_t j;
6363
int cmp;
64+
#if LINEAR_PROBES
65+
setentry *limit;
66+
size_t j;
67+
#endif
6468

6569
entry = &table[i & mask];
6670
if (entry->key == NULL)
@@ -84,6 +88,7 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
8488
if (entry->key == dummy && freeslot == NULL)
8589
freeslot = entry;
8690

91+
#if LINEAR_PROBES
8792
limit = &table[mask];
8893
for (j = 0 ; j < LINEAR_PROBES ; j++) {
8994
entry = (entry == limit) ? &table[0] : entry + 1;
@@ -106,13 +111,14 @@ set_lookkey(PySetObject *so, PyObject *key, Py_hash_t hash)
106111
if (entry->key == dummy && freeslot == NULL)
107112
freeslot = entry;
108113
}
114+
#endif
109115

110116
perturb >>= PERTURB_SHIFT;
111117
i = i * 5 + 1 + perturb;
112118

113119
entry = &table[i & mask];
114120
if (entry->key == NULL)
115-
break;
121+
goto found_null;
116122
}
117123
found_null:
118124
return freeslot == NULL ? entry : freeslot;
@@ -129,11 +135,13 @@ set_lookkey_unicode(PySetObject *so, PyObject *key, Py_hash_t hash)
129135
setentry *table = so->table;
130136
setentry *freeslot = NULL;
131137
setentry *entry;
132-
setentry *limit;
133138
size_t perturb = hash;
134139
size_t mask = so->mask;
135140
size_t i = (size_t)hash;
141+
#if LINEAR_PROBES
142+
setentry *limit;
136143
size_t j;
144+
#endif
137145

138146
/* Make sure this function doesn't have to handle non-unicode keys,
139147
including subclasses of str; e.g., one reason to subclass
@@ -157,6 +165,7 @@ set_lookkey_unicode(PySetObject *so, PyObject *key, Py_hash_t hash)
157165
if (entry->key == dummy && freeslot == NULL)
158166
freeslot = entry;
159167

168+
#if LINEAR_PROBES
160169
limit = &table[mask];
161170
for (j = 0 ; j < LINEAR_PROBES ; j++) {
162171
entry = (entry == limit) ? &table[0] : entry + 1;
@@ -170,13 +179,14 @@ set_lookkey_unicode(PySetObject *so, PyObject *key, Py_hash_t hash)
170179
if (entry->key == dummy && freeslot == NULL)
171180
freeslot = entry;
172181
}
182+
#endif
173183

174184
perturb >>= PERTURB_SHIFT;
175185
i = i * 5 + 1 + perturb;
176186

177187
entry = &table[i & mask];
178188
if (entry->key == NULL)
179-
break;
189+
goto found_null;
180190
}
181191
found_null:
182192
return freeslot == NULL ? entry : freeslot;
@@ -198,17 +208,21 @@ set_insert_clean(PySetObject *so, PyObject *key, Py_hash_t hash)
198208
size_t perturb = hash;
199209
size_t mask = (size_t)so->mask;
200210
size_t i = (size_t)hash;
211+
#if LINEAR_PROBES
201212
size_t j;
213+
#endif
202214

203215
while (1) {
204216
entry = &table[i & mask];
205217
if (entry->key == NULL)
206218
goto found_null;
219+
#if LINEAR_PROBES
207220
for (j = 1 ; j <= LINEAR_PROBES ; j++) {
208221
entry = &table[(i + j) & mask];
209222
if (entry->key == NULL)
210223
goto found_null;
211224
}
225+
#endif
212226
perturb >>= PERTURB_SHIFT;
213227
i = i * 5 + 1 + perturb;
214228
}

0 commit comments

Comments
 (0)