Skip to content

Commit bae27b3

Browse files
authored
Stable benchmarks, fourth attempt (#1208)
See #1201 for details
1 parent 8cfe02b commit bae27b3

File tree

2 files changed

+137
-48
lines changed

2 files changed

+137
-48
lines changed

multidict/_multidict_py.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -657,14 +657,17 @@ def getall(
657657
identity = self._identity(key)
658658
hash_ = hash(identity)
659659
res = []
660-
660+
restore = []
661661
for slot, idx, e in self._keys.iter_hash(hash_):
662662
if e.identity == identity: # pragma: no branch
663663
res.append(e.value)
664664
e.hash = -1
665-
self._keys.restore_hash(hash_)
665+
restore.append(idx)
666666

667667
if res:
668+
entries = self._keys.entries
669+
for idx in restore:
670+
entries[idx].hash = hash_ # type: ignore[union-attr]
668671
return res
669672
if not res and default is not sentinel:
670673
return default

tests/test_multidict_benchmarks.py

Lines changed: 132 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ def _run() -> None:
3333
def test_cimultidict_insert_istr(
3434
benchmark: BenchmarkFixture,
3535
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
36+
case_insensitive_str_class: type[istr],
3637
) -> None:
3738
md = case_insensitive_multidict_class()
38-
items = [istr(i) for i in range(100)]
39+
items = [case_insensitive_str_class(i) for i in range(100)]
3940

4041
@benchmark
4142
def _run() -> None:
@@ -60,9 +61,10 @@ def _run() -> None:
6061
def test_cimultidict_add_istr(
6162
benchmark: BenchmarkFixture,
6263
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
64+
case_insensitive_str_class: type[istr],
6365
) -> None:
6466
base_md = case_insensitive_multidict_class()
65-
items = [istr(i) for i in range(100)]
67+
items = [case_insensitive_str_class(i) for i in range(100)]
6668

6769
@benchmark
6870
def _run() -> None:
@@ -88,9 +90,13 @@ def _run() -> None:
8890
def test_cimultidict_pop_istr(
8991
benchmark: BenchmarkFixture,
9092
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
93+
case_insensitive_str_class: type[istr],
9194
) -> None:
92-
md_base = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(200))
93-
items = [istr(i) for i in range(50, 150)]
95+
md_base = case_insensitive_multidict_class(
96+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
97+
for i in range(200)
98+
)
99+
items = [case_insensitive_str_class(i) for i in range(50, 150)]
94100

95101
@benchmark
96102
def _run() -> None:
@@ -135,9 +141,16 @@ def _run() -> None:
135141
def test_cimultidict_update_istr(
136142
benchmark: BenchmarkFixture,
137143
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
144+
case_insensitive_str_class: type[istr],
138145
) -> None:
139-
md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(150))
140-
items: Dict[Union[str, istr], istr] = {istr(i): istr(i) for i in range(100, 200)}
146+
md = case_insensitive_multidict_class(
147+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
148+
for i in range(150)
149+
)
150+
items: Dict[Union[str, istr], istr] = {
151+
case_insensitive_str_class(i): case_insensitive_str_class(i)
152+
for i in range(100, 200)
153+
}
141154

142155
@benchmark
143156
def _run() -> None:
@@ -159,10 +172,17 @@ def _run() -> None:
159172
def test_cimultidict_update_istr_with_kwargs(
160173
benchmark: BenchmarkFixture,
161174
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
175+
case_insensitive_str_class: type[istr],
162176
) -> None:
163-
md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(150))
164-
items: Dict[Union[str, istr], istr] = {istr(i): istr(i) for i in range(100, 200)}
165-
kwargs = {str(i): istr(i) for i in range(200, 300)}
177+
md = case_insensitive_multidict_class(
178+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
179+
for i in range(150)
180+
)
181+
items: Dict[Union[str, istr], istr] = {
182+
case_insensitive_str_class(i): case_insensitive_str_class(i)
183+
for i in range(100, 200)
184+
}
185+
kwargs = {str(i): case_insensitive_str_class(i) for i in range(200, 300)}
166186

167187
@benchmark
168188
def _run() -> None:
@@ -185,9 +205,15 @@ def _run() -> None:
185205
def test_cimultidict_extend_istr(
186206
benchmark: BenchmarkFixture,
187207
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
208+
case_insensitive_str_class: type[istr],
188209
) -> None:
189-
base_md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100))
190-
items = {istr(i): istr(i) for i in range(200)}
210+
base_md = case_insensitive_multidict_class(
211+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
212+
for i in range(100)
213+
)
214+
items = {
215+
case_insensitive_str_class(i): case_insensitive_str_class(i) for i in range(200)
216+
}
191217

192218
@benchmark
193219
def _run() -> None:
@@ -213,10 +239,16 @@ def _run() -> None:
213239
def test_cimultidict_extend_istr_with_kwargs(
214240
benchmark: BenchmarkFixture,
215241
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
242+
case_insensitive_str_class: type[istr],
216243
) -> None:
217-
base_md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100))
218-
items = {istr(i): istr(i) for i in range(200)}
219-
kwargs = {str(i): istr(i) for i in range(200, 300)}
244+
base_md = case_insensitive_multidict_class(
245+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
246+
for i in range(100)
247+
)
248+
items = {
249+
case_insensitive_str_class(i): case_insensitive_str_class(i) for i in range(200)
250+
}
251+
kwargs = {str(i): case_insensitive_str_class(i) for i in range(200, 300)}
220252

221253
@benchmark
222254
def _run() -> None:
@@ -241,9 +273,13 @@ def _run() -> None:
241273
def test_cimultidict_delitem_istr(
242274
benchmark: BenchmarkFixture,
243275
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
276+
case_insensitive_str_class: type[istr],
244277
) -> None:
245-
md_base = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100))
246-
items = [istr(i) for i in range(100)]
278+
md_base = case_insensitive_multidict_class(
279+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
280+
for i in range(100)
281+
)
282+
items = [case_insensitive_str_class(i) for i in range(100)]
247283

248284
@benchmark
249285
def _run() -> None:
@@ -259,12 +295,13 @@ def test_multidict_getall_str_hit(
259295
(f"key{j}", str(f"{i}-{j}")) for i in range(20) for j in range(5)
260296
)
261297

298+
keys = set(md.keys())
299+
262300
@benchmark
263301
def _run() -> None:
264302
for i in range(100):
265-
md.getall("key1")
266-
md.getall("key2")
267-
md.getall("key3")
303+
for key in keys:
304+
md.getall(key)
268305

269306

270307
def test_multidict_getall_str_miss(
@@ -274,43 +311,51 @@ def test_multidict_getall_str_miss(
274311
(f"key{j}", str(f"{i}-{j}")) for i in range(20) for j in range(5)
275312
)
276313

314+
keys = {f"{key}-miss" for key in md.keys()}
315+
277316
@benchmark
278317
def _run() -> None:
279-
for i in range(100):
280-
md.getall("miss1", ())
281-
md.getall("miss2", ())
282-
md.getall("miss3", ())
318+
for key in keys:
319+
md.getall(key, ())
283320

284321

285322
def test_cimultidict_getall_istr_hit(
286323
benchmark: BenchmarkFixture,
287324
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
325+
case_insensitive_str_class: type[istr],
288326
) -> None:
289-
all_istr = [istr("key1"), istr("key2"), istr("key3")]
290327
md = case_insensitive_multidict_class(
291-
(f"key{j}", istr(f"{i}-{j}")) for i in range(20) for j in range(5)
328+
(f"key{j}", case_insensitive_str_class(f"{i}-{j}"))
329+
for i in range(20)
330+
for j in range(5)
292331
)
293332

333+
keys = set(md.keys())
334+
294335
@benchmark
295336
def _run() -> None:
296337
for i in range(100):
297-
for key in all_istr:
338+
for key in keys:
298339
md.getall(key)
299340

300341

301342
def test_cimultidict_getall_istr_miss(
302343
benchmark: BenchmarkFixture,
303344
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
345+
case_insensitive_str_class: type[istr],
304346
) -> None:
305-
miss_istr = [istr("miss-1"), istr("miss-2"), istr("miss-3")]
306347
md = case_insensitive_multidict_class(
307-
(istr(f"key{j}"), istr(f"{i}-{j}")) for i in range(20) for j in range(5)
348+
(case_insensitive_str_class(f"key{j}"), case_insensitive_str_class(f"{i}-{j}"))
349+
for i in range(20)
350+
for j in range(5)
308351
)
309352

353+
keys = {case_insensitive_str_class(f"{key}-miss") for key in md.keys()}
354+
310355
@benchmark
311356
def _run() -> None:
312357
for i in range(100):
313-
for key in miss_istr:
358+
for key in keys:
314359
md.getall(key, ())
315360

316361

@@ -329,9 +374,13 @@ def _run() -> None:
329374
def test_cimultidict_fetch_istr(
330375
benchmark: BenchmarkFixture,
331376
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
377+
case_insensitive_str_class: type[istr],
332378
) -> None:
333-
md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100))
334-
items = [istr(i) for i in range(100)]
379+
md = case_insensitive_multidict_class(
380+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
381+
for i in range(100)
382+
)
383+
items = [case_insensitive_str_class(i) for i in range(100)]
335384

336385
@benchmark
337386
def _run() -> None:
@@ -366,9 +415,13 @@ def _run() -> None:
366415
def test_cimultidict_get_istr_hit(
367416
benchmark: BenchmarkFixture,
368417
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
418+
case_insensitive_str_class: type[istr],
369419
) -> None:
370-
md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100))
371-
items = [istr(i) for i in range(100)]
420+
md = case_insensitive_multidict_class(
421+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
422+
for i in range(100)
423+
)
424+
items = [case_insensitive_str_class(i) for i in range(100)]
372425

373426
@benchmark
374427
def _run() -> None:
@@ -379,9 +432,13 @@ def _run() -> None:
379432
def test_cimultidict_get_istr_miss(
380433
benchmark: BenchmarkFixture,
381434
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
435+
case_insensitive_str_class: type[istr],
382436
) -> None:
383-
md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100))
384-
items = [istr(i) for i in range(100, 200)]
437+
md = case_insensitive_multidict_class(
438+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
439+
for i in range(100)
440+
)
441+
items = [case_insensitive_str_class(i) for i in range(100, 200)]
385442

386443
@benchmark
387444
def _run() -> None:
@@ -404,9 +461,13 @@ def _run() -> None:
404461
def test_cimultidict_get_istr_hit_with_default(
405462
benchmark: BenchmarkFixture,
406463
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
464+
case_insensitive_str_class: type[istr],
407465
) -> None:
408-
md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100))
409-
items = [istr(i) for i in range(100)]
466+
md = case_insensitive_multidict_class(
467+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
468+
for i in range(100)
469+
)
470+
items = [case_insensitive_str_class(i) for i in range(100)]
410471

411472
@benchmark
412473
def _run() -> None:
@@ -417,9 +478,13 @@ def _run() -> None:
417478
def test_cimultidict_get_istr_with_default_miss(
418479
benchmark: BenchmarkFixture,
419480
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
481+
case_insensitive_str_class: type[istr],
420482
) -> None:
421-
md = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(100))
422-
items = [istr(i) for i in range(100, 200)]
483+
md = case_insensitive_multidict_class(
484+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
485+
for i in range(100)
486+
)
487+
items = [case_insensitive_str_class(i) for i in range(100, 200)]
423488

424489
@benchmark
425490
def _run() -> None:
@@ -459,8 +524,12 @@ def _run() -> None:
459524
def test_create_cimultidict_with_items_istr(
460525
benchmark: BenchmarkFixture,
461526
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
527+
case_insensitive_str_class: type[istr],
462528
) -> None:
463-
items = [(istr(i), istr(i)) for i in range(100)]
529+
items = [
530+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
531+
for i in range(100)
532+
]
464533

465534
@benchmark
466535
def _run() -> None:
@@ -480,8 +549,11 @@ def _run() -> None:
480549
def test_create_cimultidict_with_dict_istr(
481550
benchmark: BenchmarkFixture,
482551
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
552+
case_insensitive_str_class: type[istr],
483553
) -> None:
484-
dct = {istr(i): istr(i) for i in range(100)}
554+
dct = {
555+
case_insensitive_str_class(i): case_insensitive_str_class(i) for i in range(100)
556+
}
485557

486558
@benchmark
487559
def _run() -> None:
@@ -502,9 +574,13 @@ def _run() -> None:
502574
def test_create_cimultidict_with_items_istr_with_kwargs(
503575
benchmark: BenchmarkFixture,
504576
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
577+
case_insensitive_str_class: type[istr],
505578
) -> None:
506-
items = [(istr(i), istr(i)) for i in range(100)]
507-
kwargs = {str(i): istr(i) for i in range(100)}
579+
items = [
580+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
581+
for i in range(100)
582+
]
583+
kwargs = {str(i): case_insensitive_str_class(i) for i in range(100)}
508584

509585
@benchmark
510586
def _run() -> None:
@@ -540,8 +616,12 @@ def _run() -> None:
540616

541617
def test_create_cimultidictproxy(
542618
benchmark: BenchmarkFixture,
619+
case_insensitive_str_class: type[istr],
543620
) -> None:
544-
items = [(istr(i), istr(i)) for i in range(100)]
621+
items = [
622+
(case_insensitive_str_class(i), case_insensitive_str_class(i))
623+
for i in range(100)
624+
]
545625
md = CIMultiDict(items)
546626

547627
@benchmark
@@ -552,8 +632,11 @@ def _run() -> None:
552632
def test_create_from_existing_cimultidict(
553633
benchmark: BenchmarkFixture,
554634
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
635+
case_insensitive_str_class: type[istr],
555636
) -> None:
556-
existing = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(5))
637+
existing = case_insensitive_multidict_class(
638+
(case_insensitive_str_class(i), case_insensitive_str_class(i)) for i in range(5)
639+
)
557640

558641
@benchmark
559642
def _run() -> None:
@@ -563,8 +646,11 @@ def _run() -> None:
563646
def test_copy_from_existing_cimultidict(
564647
benchmark: BenchmarkFixture,
565648
case_insensitive_multidict_class: Type[CIMultiDict[istr]],
649+
case_insensitive_str_class: type[istr],
566650
) -> None:
567-
existing = case_insensitive_multidict_class((istr(i), istr(i)) for i in range(5))
651+
existing = case_insensitive_multidict_class(
652+
(case_insensitive_str_class(i), case_insensitive_str_class(i)) for i in range(5)
653+
)
568654

569655
@benchmark
570656
def _run() -> None:

0 commit comments

Comments
 (0)