Skip to content

gh-161145: Use _Py_find_first_nonascii in the tokenizer - #161146

Open
cmaloney wants to merge 1 commit into
python:mainfrom
cmaloney:tokenizer_ascii_scan
Open

cmaloney wants to merge 1 commit into
python:mainfrom
cmaloney:tokenizer_ascii_scan

Conversation

@cmaloney

@cmaloney cmaloney commented Nov 1, 2026 •

Copy link
Copy Markdown
Contributor

Skip sequence of ASCII at once rather than one char per loop reusing faster code from unicodeobject. Can't use the checking from stringlib or unicodeobject fully because those assume copying/writing to an output buffer which slows down this case. Line numbers are only needed for the error message, so count them there. The function is exported because test_peg_generator builds the tokenizer sources into an extension module.

The check drops from about 0.9% of compile() time to about 0.1% (perf record). CPU time per compile(), PGO+LTO, 20 paired runs on one pinned core:

Workload main this runs faster
typing.py 6.72 ms 1.2% faster 17/20
all top-level Lib/*.py 241 ms 0.7% faster 17/20

_PyTokenizer_ensure_utf8 instructions during compile(), callgrind:

File main this
typing.py 1,811,154 132,909
_pydatetime.py 1,246,691 91,566
test_email/test_contentmanager.py 487,525 43,273

Skip sequence of ASCII at once rather than one char per loop reusing
faster code from unicodeobject. Can't use the checking from stringlib
or unicodeobject fully because those assume copying/writing to an output
buffer which slows down this case. Line numbers are only needed for the
error message, so count them there.  The function is exported because
test_peg_generator builds the tokenizer sources into an extension
module.

The check drops from about 0.9% of compile() time to about 0.1%
(perf record).  CPU time per compile(), PGO+LTO, 20 paired runs on one
pinned core:

| Workload | main | this | runs faster |
|---|---:|---:|---:|
| typing.py | 6.72 ms | 1.2% faster | 17/20 |
| all top-level Lib/*.py | 241 ms | 0.7% faster | 17/20 |
| synthetic CJK literals | 4.32 ms | 1.3% faster | 16/20 |

_PyTokenizer_ensure_utf8 instructions during compile(), callgrind:

| File | main | this |
|---|---:|---:|
| typing.py | 1,811,154 | 132,909 |
| _pydatetime.py | 1,246,691 | 91,566 |
| test_email/test_contentmanager.py | 487,525 | 43,273 |
| synthetic Cyrillic literals | 5,825,590 | 3,832,223 |
| synthetic CJK literals | 3,450,590 | 2,479,019 |

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@picnixz

picnixz commented Nov 1, 2026

Copy link
Copy Markdown
Member

Mmh. Benchmarks don't seem convincing. 1% faster is... quite small IMO.

@cmaloney

cmaloney commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

The diff is small and this is currently fully duplicated code. This to me is more a refactor than perf change, and sets up for "we can make decode 1.5x faster for ASCII" (the next commit).

@cmaloney

cmaloney commented Nov 1, 2026

Copy link
Copy Markdown
Contributor Author

Related to: #153568

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

awaiting review skip news type-feature A feature request or enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants