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

aio-libs / multidict / 36265956799
87%

Build:
DEFAULT BRANCH: master
Ran 26 Sep 2026 07:25PM UTC
Jobs 1
Files 44
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

26 Sep 2026 07:24PM UTC coverage: 87.113% (+0.004%) from 87.109%
36265956799

push

github

web-flow
Skip the watcher checks on unwatched deletes, replaces and pops (#1604)

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

## What do these changes do?

`del d[key]`, `d[key] = value` and `pop()` tested `md->watch` for every
event they might record. Stores and decrefs in between force a reload
each time, and the extra code made the probe loop spill. On a multidict
nobody watches, that was most of the regression #1551 left in these
rows. Each operation now reads `md->watch` once under its critical
section. When it is `NULL`, the operation runs a copy of its locked body
with no watcher code in it; the watched copy is `COLD`. The not-found
`md_add_with_hash()` call moved out of `_md_replace()` so the hot path
keeps a single inlined copy of it.

The second copies use up GCC's inline budget, which is already at
`inline-unit-growth` for this translation unit. GCC reacted by outlining
`_md_del_at()` from `popitem()` and `htkeys_set_index()` from the
free-threaded insert path. Both are now `ALWAYS_INLINE`.

Callgrind `ir_per_op`, `multidict_c`, against 2f84475 (rows that moved
by more than 0.1%):

| operation | GIL 3.14.7 | free-threaded 3.14.7t |
| --- | --- | --- |
| `del d[key]` | 250.8 -> 237.5 (-5.3%) | 408.6 -> 383.3 (-6.2%) |
| `d[key] = v`, existing key | 329.6 -> 325.5 (-1.2%) | 505.1 -> 506.9
(+0.4%) |
| `d[key] = v`, new key | 403.1 -> 398.4 (-1.2%) | 610.5 -> 609.0
(-0.2%) |
| `d.pop(key)` | 390.8 -> 389.8 (-0.3%) | 537.8 -> 533.8 (-0.7%) |
| `d.getall(key)` | flat | 856.1 -> 844.2 (-1.4%) |
| `d[key] = v`, `istr` key | 876.0 -> 884.9 (+1.0%) | 1028.8 -> 1032.6
(+0.4%) |

GIL `delitem` is back to 237.5, against 236.5 before #1551. The `istr`
setitem row is the one that got worse: the watch tests fell from 13 to 3
Ir per call, but the case-insensitive compare in the probe loop got a
worse register allocation. Every other row is unchanged.

## Are there changes in behavior for the user?

No, except in a corner of the watchers C API. A watcher that a `__del... (continued)

781 of 1562 branches covered (50.0%)

Branch coverage included in aggregate %.

10 of 11 new or added lines in 1 file covered. (90.91%)

8223 of 8774 relevant lines covered (93.72%)

1.87 hits per line

Uncovered Changes

Lines Coverage ∆ File
1
74.61
0.2% tests/test_capi.py
Jobs
ID Job ID Ran Files Coverage
1 MyPy - 36265956799.1 26 Sep 2026 07:25PM UTC 88
87.11
GitHub Action Run
Source Files on build 36265956799
  • Tree
  • List 44
  • 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 #36265956799
  • 05315a40 on github
  • Prev Build on master (#36259675904)
  • Next Build on master (#36268833535)
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