Skip to content

Commit 56fa30f

Browse files
committed
Merge remote-tracking branch 'upstream/main' into jit-refcount-call-type
2 parents bcb805d + f9704f1 commit 56fa30f

File tree

58 files changed

+7535
-838
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+7535
-838
lines changed

.gitattributes

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,10 @@ Include/opcode.h generated
8383
Include/opcode_ids.h generated
8484
Include/token.h generated
8585
Lib/_opcode_metadata.py generated
86-
Lib/keyword.py generated
8786
Lib/idlelib/help.html generated
87+
Lib/keyword.py generated
88+
Lib/pydoc_data/topics.py generated
89+
Lib/pydoc_data/module_docs.py generated
8890
Lib/test/certdata/*.pem generated
8991
Lib/test/certdata/*.0 generated
9092
Lib/test/levenshtein_examples.json generated

.github/workflows/tail-call.yml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,19 +79,17 @@ jobs:
7979
with:
8080
python-version: '3.11'
8181

82-
- name: Native Windows (debug)
82+
- name: Native Windows MSVC (release)
8383
if: runner.os == 'Windows' && matrix.architecture != 'ARM64'
8484
shell: cmd
8585
run: |
86-
choco install llvm --allow-downgrade --no-progress --version ${{ matrix.llvm }}.1.0
87-
set PlatformToolset=clangcl
88-
set LLVMToolsVersion=${{ matrix.llvm }}.1.0
89-
set LLVMInstallDir=C:\Program Files\LLVM
90-
call ./PCbuild/build.bat --tail-call-interp -d -p ${{ matrix.architecture }}
91-
call ./PCbuild/rt.bat -d -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
86+
choco install visualstudio2026buildtools --no-progress -y --force --params "--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --locale en-US --passive"
87+
$env:PATH = "C:\Program Files (x86)\Microsoft Visual Studio\18\BuildTools\MSBuild\Current\bin;$env:PATH"
88+
./PCbuild/build.bat --tail-call-interp -c Release -p ${{ matrix.architecture }} "/p:PlatformToolset=v145"
89+
./PCbuild/rt.bat -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
9290
9391
# No tests (yet):
94-
- name: Emulated Windows (release)
92+
- name: Emulated Windows Clang (release)
9593
if: runner.os == 'Windows' && matrix.architecture == 'ARM64'
9694
shell: cmd
9795
run: |

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@ repos:
4040
files: ^Apple
4141
- id: ruff-format
4242
name: Run Ruff (format) on Doc/
43-
args: [--check]
43+
args: [--exit-non-zero-on-fix]
4444
files: ^Doc/
4545
- id: ruff-format
4646
name: Run Ruff (format) on Tools/build/check_warnings.py
47-
args: [--check, --config=Tools/build/.ruff.toml]
47+
args: [--exit-non-zero-on-fix, --config=Tools/build/.ruff.toml]
4848
files: ^Tools/build/check_warnings.py
4949
- id: ruff-format
5050
name: Run Ruff (format) on Tools/wasm/
51-
args: [--check, --config=Tools/wasm/.ruff.toml]
51+
args: [--exit-non-zero-on-fix, --config=Tools/wasm/.ruff.toml]
5252
files: ^Tools/wasm/
5353

5454
- repo: https://github.com/psf/black-pre-commit-mirror

Doc/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,8 @@ doctest:
140140
pydoc-topics: BUILDER = pydoc-topics
141141
pydoc-topics: build
142142
@echo "Building finished; now run this:" \
143-
"cp build/pydoc-topics/topics.py ../Lib/pydoc_data/topics.py"
143+
"cp build/pydoc-topics/topics.py ../Lib/pydoc_data/topics.py" \
144+
"&& cp build/pydoc-topics/module_docs.py ../Lib/pydoc_data/module_docs.py"
144145

145146
.PHONY: gettext
146147
gettext: BUILDER = gettext

Doc/library/profiling.sampling.rst

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,36 @@ On most systems, attaching to another process requires appropriate permissions.
200200
See :ref:`profiling-permissions` for platform-specific requirements.
201201

202202

203+
.. _replay-command:
204+
205+
The ``replay`` command
206+
----------------------
207+
208+
The ``replay`` command converts binary profile files to other output formats::
209+
210+
python -m profiling.sampling replay profile.bin
211+
python -m profiling.sampling replay --flamegraph -o profile.html profile.bin
212+
213+
This command is useful when you have captured profiling data in binary format
214+
and want to analyze it later or convert it to a visualization format. Binary
215+
profiles can be replayed multiple times to different formats without
216+
re-profiling.
217+
218+
::
219+
220+
# Convert binary to pstats (default, prints to stdout)
221+
python -m profiling.sampling replay profile.bin
222+
223+
# Convert binary to flame graph
224+
python -m profiling.sampling replay --flamegraph -o output.html profile.bin
225+
226+
# Convert binary to gecko format for Firefox Profiler
227+
python -m profiling.sampling replay --gecko -o profile.json profile.bin
228+
229+
# Convert binary to heatmap
230+
python -m profiling.sampling replay --heatmap -o my_heatmap profile.bin
231+
232+
203233
Profiling in production
204234
-----------------------
205235

@@ -1041,6 +1071,59 @@ intuitive view that shows exactly where time is spent without requiring
10411071
interpretation of hierarchical visualizations.
10421072

10431073

1074+
Binary format
1075+
-------------
1076+
1077+
Binary format (:option:`--binary`) produces a compact binary file for efficient
1078+
storage of profiling data::
1079+
1080+
python -m profiling.sampling run --binary -o profile.bin script.py
1081+
python -m profiling.sampling attach --binary -o profile.bin 12345
1082+
1083+
The :option:`--compression` option controls data compression:
1084+
1085+
- ``auto`` (default): Use zstd compression if available, otherwise no
1086+
compression
1087+
- ``zstd``: Force zstd compression (requires :mod:`compression.zstd` support)
1088+
- ``none``: Disable compression
1089+
1090+
::
1091+
1092+
python -m profiling.sampling run --binary --compression=zstd -o profile.bin script.py
1093+
1094+
To analyze binary profiles, use the :ref:`replay-command` to convert them to
1095+
other formats like flame graphs or pstats output.
1096+
1097+
1098+
Record and replay workflow
1099+
==========================
1100+
1101+
The binary format combined with the replay command enables a record-and-replay
1102+
workflow that separates data capture from analysis. Rather than generating
1103+
visualizations during profiling, you capture raw data to a compact binary file
1104+
and convert it to different formats later.
1105+
1106+
This approach has three main benefits:
1107+
1108+
- Sampling runs faster because the work of building data structures for
1109+
visualization is deferred until replay.
1110+
- A single binary capture can be converted to multiple output formats
1111+
without re-profiling: pstats for a quick overview, flame graph for visual
1112+
exploration, heatmap for line-level detail.
1113+
- Binary files are compact and easy to share with colleagues who can convert
1114+
them to their preferred format.
1115+
1116+
A typical workflow::
1117+
1118+
# Capture profile in production or during tests
1119+
python -m profiling.sampling attach --binary -o profile.bin 12345
1120+
1121+
# Later, analyze with different formats
1122+
python -m profiling.sampling replay profile.bin
1123+
python -m profiling.sampling replay --flamegraph -o profile.html profile.bin
1124+
python -m profiling.sampling replay --heatmap -o heatmap profile.bin
1125+
1126+
10441127
Live mode
10451128
=========
10461129

@@ -1252,6 +1335,10 @@ Global options
12521335

12531336
Attach to and profile a running process by PID.
12541337

1338+
.. option:: replay
1339+
1340+
Convert a binary profile file to another output format.
1341+
12551342

12561343
Sampling options
12571344
----------------
@@ -1335,12 +1422,22 @@ Output options
13351422

13361423
Generate HTML heatmap with line-level sample counts.
13371424

1425+
.. option:: --binary
1426+
1427+
Generate high-performance binary format for later conversion with the
1428+
``replay`` command.
1429+
1430+
.. option:: --compression <type>
1431+
1432+
Compression for binary format: ``auto`` (use zstd if available, default),
1433+
``zstd``, or ``none``.
1434+
13381435
.. option:: -o <path>, --output <path>
13391436

13401437
Output file or directory path. Default behavior varies by format:
1341-
``--pstats`` writes to stdout, ``--flamegraph`` and ``--gecko`` generate
1342-
files like ``flamegraph.PID.html``, and ``--heatmap`` creates a directory
1343-
named ``heatmap_PID``.
1438+
:option:`--pstats` writes to stdout, while other formats generate a file
1439+
named ``<format>_<PID>.<ext>`` (for example, ``flamegraph_12345.html``).
1440+
:option:`--heatmap` creates a directory named ``heatmap_<PID>``.
13441441

13451442

13461443
pstats display options

Doc/tools/extensions/pydoc_topics.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ class PydocTopicsBuilder(TextBuilder):
109109
def init(self) -> None:
110110
super().init()
111111
self.topics: dict[str, str] = {}
112+
self.module_docs: dict[str, str] = {}
112113

113114
def get_outdated_docs(self) -> str:
114115
# Return a string describing what an update build will build.
@@ -130,6 +131,15 @@ def write_documents(self, _docnames: Set[str]) -> None:
130131
continue
131132
doc_labels.setdefault(docname, []).append((topic_label, label_id))
132133

134+
py_domain = env.domains['py']
135+
for module_name, module_info in py_domain.data['modules'].items():
136+
docname = module_info[0]
137+
if docname.startswith('library/'):
138+
doc_file = docname.replace('library/', '')
139+
self.module_docs[module_name] = (
140+
f"{doc_file}#module-{module_name}"
141+
)
142+
133143
for docname, label_ids in status_iterator(
134144
doc_labels.items(),
135145
"building topics... ",
@@ -161,6 +171,22 @@ def finish(self) -> None:
161171
"""
162172
self.outdir.joinpath("topics.py").write_text(topics, encoding="utf-8")
163173

174+
module_docs_repr = "\n".join(
175+
f" '{module}': '{doc_file}',"
176+
for module, doc_file in sorted(self.module_docs.items())
177+
)
178+
module_docs = f"""\
179+
# Autogenerated by Sphinx on {asctime()}
180+
# as part of the release process.
181+
182+
module_docs = {{
183+
{module_docs_repr}
184+
}}
185+
"""
186+
self.outdir.joinpath("module_docs.py").write_text(
187+
module_docs, encoding="utf-8"
188+
)
189+
164190

165191
def _display_labels(item: tuple[str, Sequence[tuple[str, str]]]) -> str:
166192
_docname, label_ids = item

Doc/whatsnew/3.15.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,16 @@ zlib
849849
Optimizations
850850
=============
851851

852+
* Builds using Visual Studio 2026 (MSVC 18) may now use the new
853+
:ref:`tail-calling interpreter <whatsnew314-tail-call-interpreter>`.
854+
Results on an early experimental MSVC compiler reported roughly 15% speedup
855+
on the geometric mean of pyperformance on Windows x86-64 over
856+
the switch-case interpreter. We have
857+
observed speedups ranging from 15% for large pure-Python libraries
858+
to 40% for long-running small pure-Python scripts on Windows.
859+
(Contributed by Chris Eibl, Ken Jin, and Brandt Bucher in :gh:`143068`.
860+
Special thanks to the MSVC team including Hulon Jenkins.)
861+
852862
csv
853863
---
854864

Include/internal/pycore_ceval.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,17 @@ _Py_VectorCall_StackRefSteal(
415415
int total_args,
416416
_PyStackRef kwnames);
417417

418+
PyAPI_FUNC(PyObject*)
419+
_Py_VectorCallInstrumentation_StackRefSteal(
420+
_PyStackRef callable,
421+
_PyStackRef* arguments,
422+
int total_args,
423+
_PyStackRef kwnames,
424+
bool call_instrumentation,
425+
_PyInterpreterFrame* frame,
426+
_Py_CODEUNIT* this_instr,
427+
PyThreadState* tstate);
428+
418429
PyAPI_FUNC(PyObject *)
419430
_Py_BuiltinCallFast_StackRefSteal(
420431
_PyStackRef callable,
@@ -464,6 +475,11 @@ _Py_assert_within_stack_bounds(
464475
_PyInterpreterFrame *frame, _PyStackRef *stack_pointer,
465476
const char *filename, int lineno);
466477

478+
// Like PyMapping_GetOptionalItem, but returns the PyObject* instead of taking
479+
// it as an out parameter. This helps MSVC's escape analysis when used with
480+
// tail calling.
481+
PyAPI_FUNC(PyObject*) _PyMapping_GetOptionalItem2(PyObject* obj, PyObject* key, int* err);
482+
467483
#ifdef __cplusplus
468484
}
469485
#endif

Include/internal/pycore_global_objects_fini_generated.h

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)