Reduce overhead of PyErr_CheckSignals
Dieses Issue hat noch niemand übernommen.
- Vorherrschende Sprache
- Python
- Sterne
- 77.2k
- Forks
- 35.9k
- PR-Merge-Kennzahlen
- PR-Kennzahlen ausstehend
Beschreibung
Feature or enhancement
Proposal:
PyErr_CheckSignals() is the API long-running C loops use to stay interruptible. In the common case (no signal arrived) the call currently does, in order:
_PyRunRemoteDebugger()(since gh-131591, 3.14): a call that fetches the interpreter config via_PyInterpreterState_GetConfig()before looking at the pending flag;_Py_ThreadCanHandleSignals():_Py_IsMainThread()callsPyThread_get_thread_ident()and thereforepthread_self(), plus_Py_IsMainInterpreter();- only then
_PyErr_CheckSignalsTstate(), whose first line is the cheapis_trippedtest that returns immediately.
That is about 100 instructions per call.
Proposal
Test the cheap flags first, without changing what is done when they are set:
_PyErr_CheckSignalsTstate()does the main-thread check itself, after its existingis_trippedtest, soPyErr_CheckSignals()and the eval loop just call it; the handler-running body moves to an out-of-line helper so the early return stays cheap;_PyRunRemoteDebugger()testsdebugger_pending_callbefore fetching the config.
Results
Non-PGO build, pyperf:
| Benchmark | main | branch |
|---|---|---|
| str(12345) | 68.6 ns | 56.8 ns: 1.21x faster |
| repr(list(range(100))) | 3.06 us | 2.36 us: 1.29x faster |
| ', '.join(map(str, range(100))) | 6.90 us | 5.67 us: 1.22x faster |
| '%s=%r' % (k, v) | 192 ns | 177 ns: 1.08x faster |
| print(*range(100), file=f) | 15.6 us | 13.5 us: 1.16x faster |
| csv.writer: 100 rows of 10 ints | 72.5 us | 60.1 us: 1.21x faster |
| repr(dataclass with 5 fields) | 805 ns | 720 ns: 1.12x faster |
| a * b (10 x 10 digits) | 159 ns | 102 ns: 1.56x faster |
| a // c (10 // 2 digits) | 151 ns | 121 ns: 1.24x faster |
Notes: the gain for the arithmetic cases are not too important, they can be handled directly as well. See https://github.com/python/cpython/issues/157742.
Has this already been discussed elsewhere?
Related: gh-131591, gh-133465
Has this already been discussed elsewhere?
No response given
Links to previous discussion of this feature:
No response
Linked PRs
- gh-157748
Beitragsleitfaden
Erste Schritte
- Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
- Forke das Repository und arbeite in einem Branch.
- Öffne einen Pull Request, der die Issue-Nummer nennt.
Rechercherichtung
Beginne mit dem Lesen von PyErr_CheckSignals(), _PyErr_CheckSignalsTstate() und _PyRunRemoteDebugger und konzentriere dich dabei auf die angegebene Reihenfolge der kostengünstigen Flag-Prüfungen und der Signalverarbeitung. Vergleiche das vorgeschlagene Verhalten und die Benchmarks mit dem verknüpften PR gh-157748; das Issue ist abgeschlossen, wenn der Pfad ohne Signale kostengünstiger ist, ohne das Verhalten zu ändern, wenn Flags gesetzt sind.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- c, python
- Bereich
- performance
- Issue-Typ
- Feature
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Aktivitätsstatus
- Veraltet
- Klarheit
- Klar beschrieben
- Anfängerfreundlichkeit
- 25/100