GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-119396: Optimize PyUnicode_FromFormat() UTF-8 decoder by vstinner · Pull Request #119398 · python/cpython

Conversation

@vstinner

@vstinner vstinner commented May 22, 2024 •
edited by bedevere-app Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Add unicode_decode_utf8_writer() to write directly characters into a _PyUnicodeWriter writer: avoid the creation of a temporary string. Optimize PyUnicode_FromFormat() by using the new
unicode_decode_utf8_writer().

Rename unicode_fromformat_write_cstr() to
unicode_fromformat_write_utf8().

Microbenchmark on the code:

return PyUnicode_FromFormat(
    "%s %s %s %s %s.",
    "format", "multiple", "utf8", "short", "strings");

Result: 620 ns +- 8 ns -> 382 ns +- 2 ns: 1.62x faster.

  • Issue: [C API] Add an efficient public PyUnicodeWriter API #119182
  • Issue: Optimize _PyUnicodeWriter implementation #119396

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@vstinner vstinner added the skip news label May 22, 2024
@bedevere-app bedevere-app Bot added the awaiting core review label May 22, 2024
@bedevere-app bedevere-app Bot mentioned this pull request May 22, 2024
[C API] Add an efficient public PyUnicodeWriter API #119182
Closed
@vstinner

vstinner commented May 22, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Benchmark:

diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index f99ebf0dde..0752b2b1d2 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -3312,6 +3312,14 @@ function_set_warning(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
     Py_RETURN_NONE;
 }
 
+static PyObject *
+bench(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
+{
+    return PyUnicode_FromFormat(
+        "%s %s %s %s %s.",
+        "format", "multiple", "utf8", "short", "strings");
+}
+
 static PyMethodDef TestMethods[] = {
     {"set_errno",               set_errno,                       METH_VARARGS},
     {"test_config",             test_config,                     METH_NOARGS},
@@ -3454,6 +3462,7 @@ static PyMethodDef TestMethods[] = {
     {"check_pyimport_addmodule", check_pyimport_addmodule, METH_VARARGS},
     {"test_weakref_capi", test_weakref_capi, METH_NOARGS},
     {"function_set_warning", function_set_warning, METH_NOARGS},
+    {"bench", bench, METH_NOARGS},
     {NULL, NULL} /* sentinel */
 };

Command:

./python -m venv env
env/bin/python -m pip install pyperf
env/bin/python -m pyperf timeit -s 'import _testcapi; func=_testcapi.bench' 'func()' -v -o ref.json

Result, Python built with gcc -O3:

620 ns +- 8 ns -> 382 ns +- 2 ns: 1.62x faster

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner
vstinner force-pushed the utf8_writer branch from 6c8aedc to d3fe16f Compare May 22, 2024 14:40
@vstinner

vstinner commented May 22, 2024

Copy link
Copy Markdown
Member Author

Oh, there was a performance regression on b"abc".decode(): I fixed it.

Benchmark:

import pyperf
import _testcapi
runner = pyperf.Runner()

utf8 = b'abc'
runner.bench_func('abc', utf8.decode)

utf8 = 'abcé'.encode()
runner.bench_func('abc + UTF-8', utf8.decode)

utf8 = 'éabc'.encode()
runner.bench_func('UTF-8 + abc', utf8.decode)

utf8 = b'x' * (1024 * 1024)
runner.bench_func('ASCII 1 MiB', utf8.decode)

utf8 = ('x' * (1024 * 1024) + 'é').encode()
runner.bench_func('ASCII 1 MiB + UTF-8', utf8.decode)

utf8 = ('é' + 'x' * (1024 * 1024)).encode()
runner.bench_func('UTF-8 + ASCII 1 MiB', utf8.decode)

utf8 = ('€' + 'x' * (1024 * 1024)).encode()
runner.bench_func('UTF-8 euro + ASCII 1 MiB', utf8.decode)

Results, Python built with gcc -O3, CPU isolation.

+---------------------+---------+-----------------------+
| Benchmark           | ref     | change                |
+=====================+=========+=======================+
| abc                 | 73.7 ns | 74.7 ns: 1.01x slower |
+---------------------+---------+-----------------------+
| abc + UTF-8         | 167 ns  | 172 ns: 1.03x slower  |
+---------------------+---------+-----------------------+
| ASCII 1 MiB         | 118 us  | 118 us: 1.00x faster  |
+---------------------+---------+-----------------------+
| ASCII 1 MiB + UTF-8 | 1.08 ms | 1.07 ms: 1.00x faster |
+---------------------+---------+-----------------------+
| UTF-8 + ASCII 1 MiB | 572 us  | 570 us: 1.00x faster  |
+---------------------+---------+-----------------------+
| Geometric mean      | (ref)   | 1.00x slower          |
+---------------------+---------+-----------------------+

Benchmark hidden because not significant (2): UTF-8 + abc, UTF-8 euro + ASCII 1 MiB

=> There is no significant impact on bytes.decode() performance (no slow down).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented May 22, 2024

Copy link
Copy Markdown
Member Author

cc @serhiy-storchaka

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

serhiy-storchaka
serhiy-storchaka approved these changes May 22, 2024
View reviewed changes

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Objects/unicodeobject.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Objects/unicodeobject.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting core review labels May 22, 2024
vstinner added 3 commits May 22, 2024 21:17
@vstinner
pythongh-119182: Optimize PyUnicode_FromFormat() UTF-8 decoder
33b1c4a
Add unicode_decode_utf8_writer() to write directly characters into a
_PyUnicodeWriter writer: avoid the creation of a temporary string.
Optimize PyUnicode_FromFormat() by using the new
unicode_decode_utf8_writer().

Rename unicode_fromformat_write_cstr() to
unicode_fromformat_write_utf8().

Microbenchmark on the code:

    return PyUnicode_FromFormat(
        "%s %s %s %s %s.",
        "format", "multiple", "utf8", "short", "strings");

Result: 620 ns +- 8 ns -> 382 ns +- 2 ns: 1.62x faster.
@vstinner
Fix unicode_decode_utf8() perf regression
99f4b13
@vstinner
Address review
d496db8
@vstinner
vstinner force-pushed the utf8_writer branch from d3fe16f to d496db8 Compare May 22, 2024 19:19
@vstinner
vstinner enabled auto-merge (squash) May 22, 2024 19:20
@vstinner

vstinner commented May 22, 2024

Copy link
Copy Markdown
Member Author

I enabled automerge. Thanks for the review @serhiy-storchaka.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner
vstinner disabled auto-merge May 22, 2024 20:45
@vstinner
vstinner enabled auto-merge (squash) May 22, 2024 20:45
@vstinner vstinner changed the title gh-119182: Optimize PyUnicode_FromFormat() UTF-8 decoder gh-119398: Optimize PyUnicode_FromFormat() UTF-8 decoder May 22, 2024
@vstinner vstinner changed the title gh-119398: Optimize PyUnicode_FromFormat() UTF-8 decoder gh-119396: Optimize PyUnicode_FromFormat() UTF-8 decoder May 22, 2024
@bedevere-app bedevere-app Bot mentioned this pull request May 22, 2024
Optimize _PyUnicodeWriter implementation #119396
Closed
@vstinner
vstinner merged commit 9b422fc into python:main May 22, 2024
@vstinner
vstinner deleted the utf8_writer branch May 22, 2024 21:05
@bedevere-app bedevere-app Bot removed the awaiting merge label May 22, 2024
estyxx pushed a commit to estyxx/cpython that referenced this pull request Jul 17, 2024
@vstinner @estyxx
pythongh-119396: Optimize PyUnicode_FromFormat() UTF-8 decoder (pytho…
ccea93d
…n#119398)

Add unicode_decode_utf8_writer() to write directly characters into a
_PyUnicodeWriter writer: avoid the creation of a temporary string.
Optimize PyUnicode_FromFormat() by using the new
unicode_decode_utf8_writer().

Rename unicode_fromformat_write_cstr() to
unicode_fromformat_write_utf8().

Microbenchmark on the code:

    return PyUnicode_FromFormat(
        "%s %s %s %s %s.",
        "format", "multiple", "utf8", "short", "strings");

Result: 620 ns +- 8 ns -> 382 ns +- 2 ns: 1.62x faster.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@serhiy-storchaka serhiy-storchaka serhiy-storchaka approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

skip news

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@vstinner @serhiy-storchaka
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.