• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

aio-libs / multidict / 37220670984
86%

Build:
DEFAULT BRANCH: master
Ran 04 Oct 2026 05:29PM UTC
Jobs 1
Files 49
Run time 1min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

04 Oct 2026 05:28PM UTC coverage: 85.962% (-0.05%) from 86.01%
37220670984

push

github

web-flow
Walk a table's entries in one loop per kind (#1676)

<!-- Thank you for your contribution! -->

## What do these changes do?

The linear walks over a table's entries read the kind once and passed it
to every accessor, leaving GCC to split each loop per kind, which #1659
and #1674 showed it does only for some spellings. Each walk now
dispatches on the kind once and runs an `ALWAYS_INLINE` body with the
kind a constant, stepping a pointer by the entry size (`entry_next()`)
instead of multiplying an index. Converted: `md == md`, `update()` /
`extend()` / `merge()` from a multidict of the same class,
`extend(self)`, `to_dict()`, `==` against a mapping, the rebuild of a
table with holes, `tp_traverse` and the C API walk over all items. The
copy and dispose loops, already split per kind, now step a pointer too.

`md_eq()` can see a value's `__eq__` move either table to the full
layout mid-compare; it then carries on from the same positions under the
new kinds. A new test drives that path on both sides and checks the
result against the pure-Python backend.

The probe loops (lookups, deletes, replace, the per-item search in
`update()`) are unchanged: splitting them the same way grew `.text` by
43% on GIL and made CIMultiDict lookups 1-1.6% slower on GIL, since a
probe chain is one or two steps.

Callgrind, base `e81a9413`, Ir per operation, MultiDict / CIMultiDict:

| Operation | GIL | FT |
|---|---|---|
| `md == md` | -41% / -46% | -35% / -47% |
| `merge(md)` | -18% / -16% | -10% / -15% |
| `extend(md)` | -9% / -5% | -9% / -7% |
| `update(md)` | -5% / -5% | -7% / -4% |
| add into a table with holes | -7% / -8% | -5% / -6% |
| GC traverse | -6% / -6% | -3% / -3% |
| `copy()` | -4% / -2% | -3% / -1% |
| `clear()` | -4% / -3% | -3% / -2% |

Nothing regressed by more than 0.8% (FT `update(items)` +0.8%, FT
CIMultiDict constructor +0.6..0.8%). FT `d[key]` -4.5% and FT `items()`
iteration -3% come from code layout, since this change does not touch
those paths. `.t... (continued)

792 of 1584 branches covered (50.0%)

Branch coverage included in aggregate %.

9 of 17 new or added lines in 1 file covered. (52.94%)

9324 of 10184 relevant lines covered (91.56%)

1.83 hits per line

Uncovered Changes

Lines Coverage ∆ File
8
42.2
0.69% tests/test_table_kinds.py
Jobs
ID Job ID Ran Files Coverage
1 MyPy - 37220670984.1 04 Oct 2026 05:29PM UTC 98
85.96
GitHub Action Run
Source Files on build 37220670984
  • Tree
  • List 49
  • Changed 3
  • Source Changed 1
  • Coverage Changed 3
Coverage ∆ File Lines Relevant Covered Missed Hits/Line Branch Hits Branch Misses
  • Back to Repo
  • Github Actions Build #37220670984
  • 598bcb81 on github
  • Prev Build on master (#37211102432)
  • Next Build on master (#37223883328)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc