Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 27 additions & 3 deletions .github/workflows/jit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ jobs:
- true
- false
llvm:
- 19
- 20
include:
- target: i686-pc-windows-msvc/msvc
architecture: Win32
Expand Down Expand Up @@ -138,7 +138,7 @@ jobs:
fail-fast: false
matrix:
llvm:
- 19
- 20
steps:
- uses: actions/checkout@v4
with:
Expand Down Expand Up @@ -166,7 +166,7 @@ jobs:
fail-fast: false
matrix:
llvm:
- 19
- 20
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -183,3 +183,27 @@ jobs:
- name: Run tests without optimizations
run: |
PYTHON_UOPS_OPTIMIZE=0 ./python -m test --multiprocess 0 --timeout 4500 --verbose2 --verbose3

tail-call-jit:
name: JIT with tail calling interpreter
needs: interpreter
runs-on: ubuntu-24.04
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
llvm:
- 20
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Build with JIT and tailcall
run: |
sudo bash -c "$(wget -O - https://apt.llvm.org/llvm.sh)" ./llvm.sh ${{ matrix.llvm }}
export PATH="$(llvm-config-${{ matrix.llvm }} --bindir):$PATH"
CC=clang-${{ matrix.llvm }} ./configure --enable-experimental-jit --with-tail-call-interp --with-pydebug
make all --jobs 4
14 changes: 7 additions & 7 deletions .github/workflows/reusable-wasi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,24 +60,24 @@ jobs:
with:
path: ${{ env.CROSS_BUILD_PYTHON }}/config.cache
# Include env.pythonLocation in key to avoid changes in environment when setup-python updates Python.
# Include the hash of `Tools/wasm/wasi.py` as it may change the environment variables.
# Include the hash of `Tools/wasm/wasi/__main__.py` as it may change the environment variables.
# (Make sure to keep the key in sync with the other config.cache step below.)
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ env.WASI_SDK_VERSION }}-${{ env.WASMTIME_VERSION }}-${{ inputs.config_hash }}-${{ hashFiles('Tools/wasm/wasi.py') }}-${{ env.pythonLocation }}
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ env.WASI_SDK_VERSION }}-${{ env.WASMTIME_VERSION }}-${{ inputs.config_hash }}-${{ hashFiles('Tools/wasm/wasi/__main__.py') }}-${{ env.pythonLocation }}
- name: "Configure build Python"
run: python3 Tools/wasm/wasi.py configure-build-python -- --config-cache --with-pydebug
run: python3 Tools/wasm/wasi configure-build-python -- --config-cache --with-pydebug
- name: "Make build Python"
run: python3 Tools/wasm/wasi.py make-build-python
run: python3 Tools/wasm/wasi make-build-python
- name: "Restore host config.cache"
uses: actions/cache@v4
with:
path: ${{ env.CROSS_BUILD_WASI }}/config.cache
# Should be kept in sync with the other config.cache step above.
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ env.WASI_SDK_VERSION }}-${{ env.WASMTIME_VERSION }}-${{ inputs.config_hash }}-${{ hashFiles('Tools/wasm/wasi.py') }}-${{ env.pythonLocation }}
key: ${{ github.job }}-${{ env.IMAGE_OS_VERSION }}-${{ env.WASI_SDK_VERSION }}-${{ env.WASMTIME_VERSION }}-${{ inputs.config_hash }}-${{ hashFiles('Tools/wasm/wasi/__main__.py') }}-${{ env.pythonLocation }}
- name: "Configure host"
# `--with-pydebug` inferred from configure-build-python
run: python3 Tools/wasm/wasi.py configure-host -- --config-cache
run: python3 Tools/wasm/wasi configure-host -- --config-cache
- name: "Make host"
run: python3 Tools/wasm/wasi.py make-host
run: python3 Tools/wasm/wasi make-host
- name: "Display build info"
run: make --directory "${CROSS_BUILD_WASI}" pythoninfo
- name: "Test"
Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/cell.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Cell Objects

"Cell" objects are used to implement variables referenced by multiple scopes.
For each such variable, a cell object is created to store the value; the local
variables of each stack frame that references the value contains a reference to
variables of each stack frame that references the value contain a reference to
the cells from outer scopes which also use that variable. When the value is
accessed, the value contained in the cell is used instead of the cell object
itself. This de-referencing of the cell object requires support from the
Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/complex.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Complex Number Objects

.. c:type:: Py_complex

This C structure defines export format for a Python complex
This C structure defines an export format for a Python complex
number object.

.. c:member:: double real
Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/datetime.rst
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ macros.

.. c:var:: PyTypeObject PyDateTime_DeltaType
This instance of :c:type:`PyTypeObject` represents Python type for
This instance of :c:type:`PyTypeObject` represents the Python type for
the difference between two datetime values;
it is the same object as :class:`datetime.timedelta` in the Python layer.

Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/descriptor.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ found in the dictionary of type objects.

.. c:function:: int PyDescr_IsData(PyObject *descr)

Return non-zero if the descriptor objects *descr* describes a data attribute, or
Return non-zero if the descriptor object *descr* describes a data attribute, or
``0`` if it describes a method. *descr* must be a descriptor object; there is
no error checking.

Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/init_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ Error Handling
* Set *\*err_msg* and return ``1`` if an error is set.
* Set *\*err_msg* to ``NULL`` and return ``0`` otherwise.

An error message is an UTF-8 encoded string.
An error message is a UTF-8 encoded string.

If *config* has an exit code, format the exit code as an error
message.
Expand Down
4 changes: 2 additions & 2 deletions Doc/c-api/mapping.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and

.. note::

Exceptions which occur when this calls :meth:`~object.__getitem__`
Exceptions which occur when this calls the :meth:`~object.__getitem__`
method are silently ignored.
For proper error handling, use :c:func:`PyMapping_HasKeyWithError`,
:c:func:`PyMapping_GetOptionalItem` or :c:func:`PyObject_GetItem()` instead.
Expand All @@ -116,7 +116,7 @@ See also :c:func:`PyObject_GetItem`, :c:func:`PyObject_SetItem` and

.. note::

Exceptions that occur when this calls :meth:`~object.__getitem__`
Exceptions that occur when this calls the :meth:`~object.__getitem__`
method or while creating the temporary :class:`str`
object are silently ignored.
For proper error handling, use :c:func:`PyMapping_HasKeyStringWithError`,
Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/marshal.rst
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ The following functions allow marshalled values to be read back in.
assumes that no further objects will be read from the file, allowing it to
aggressively load file data into memory so that the de-serialization can
operate from data in memory rather than reading a byte at a time from the
file. Only use these variant if you are certain that you won't be reading
file. Only use this variant if you are certain that you won't be reading
anything else from the file.
On error, sets the appropriate exception (:exc:`EOFError`, :exc:`ValueError`
Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/memory.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ All allocating functions belong to one of three different "domains" (see also
strategies and are optimized for different purposes. The specific details on
how every domain allocates memory or what internal functions each domain calls
is considered an implementation detail, but for debugging purposes a simplified
table can be found at :ref:`here <default-memory-allocators>`.
table can be found at :ref:`default-memory-allocators`.
The APIs used to allocate and free a block of memory must be from the same domain.
For example, :c:func:`PyMem_Free` must be used to free memory allocated using :c:func:`PyMem_Malloc`.

Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/module.rst
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ Module Objects
created, or ``NULL`` if the module wasn't created from a definition.

On error, return ``NULL`` with an exception set.
Use :c:func:`PyErr_Occurred` to tell this case apart from a mising
Use :c:func:`PyErr_Occurred` to tell this case apart from a missing
:c:type:`!PyModuleDef`.


Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/monitoring.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ Managing the Monitoring State
-----------------------------

Monitoring states can be managed with the help of monitoring scopes. A scope
would typically correspond to a python function.
would typically correspond to a Python function.

.. c:function:: int PyMonitoring_EnterScope(PyMonitoringState *state_array, uint64_t *version, const uint8_t *event_types, Py_ssize_t length)

Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/object.rst
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Object Protocol

Flag to be used with multiple functions that print the object (like
:c:func:`PyObject_Print` and :c:func:`PyFile_WriteObject`).
If passed, these function would use the :func:`str` of the object
If passed, these functions use the :func:`str` of the object
instead of the :func:`repr`.


Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/stable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ The full API is described below for advanced use cases.

.. c:member:: uint8_t abiinfo_minor_version

The major version of :c:struct:`PyABIInfo`.
The minor version of :c:struct:`PyABIInfo`.
Must be set to ``0``; larger values are reserved for backwards-compatible
future versions of :c:struct:`!PyABIInfo`.

Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/tuple.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Tuple Objects
.. c:function:: Py_ssize_t PyTuple_Size(PyObject *p)

Take a pointer to a tuple object, and return the size of that tuple.
On error, return ``-1`` and with an exception set.
On error, return ``-1`` with an exception set.


.. c:function:: Py_ssize_t PyTuple_GET_SIZE(PyObject *p)
Expand Down
2 changes: 1 addition & 1 deletion Doc/c-api/veryhigh.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ the same library that the Python runtime is using.
interpreter prompt is about to become idle and wait for user input
from the terminal. The return value is ignored. Overriding this
hook can be used to integrate the interpreter's prompt with other
event loops, as done in the :file:`Modules/_tkinter.c` in the
event loops, as done in :file:`Modules/_tkinter.c` in the
Python source code.

.. versionchanged:: 3.12
Expand Down
2 changes: 1 addition & 1 deletion Doc/library/codecs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,7 @@ alias for the ``'utf_8'`` codec.
refer to the source :source:`aliases.py <Lib/encodings/aliases.py>` file.

On Windows, ``cpXXX`` codecs are available for all code pages.
But only codecs listed in the following table are guarantead to exist on
But only codecs listed in the following table are guaranteed to exist on
other platforms.

.. impl-detail::
Expand Down
2 changes: 1 addition & 1 deletion Doc/library/idle.rst
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ New Indent Width
Open a dialog to change indent width. The accepted default by the Python
community is 4 spaces.

Strip Trailing Chitespace
Strip Trailing Whitespace
Remove trailing space and other whitespace characters after the last
non-whitespace character of a line by applying str.rstrip to each line,
including lines within multiline strings. Except for Shell windows,
Expand Down
24 changes: 24 additions & 0 deletions Include/cpython/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,15 @@ struct _ts {
*/
PyObject *threading_local_sentinel;
_PyRemoteDebuggerSupport remote_debugger_support;

#ifdef Py_STATS
// Pointer to PyStats structure, NULL if recording is off. For the
// free-threaded build, the structure is per-thread (stored as a pointer
// in _PyThreadStateImpl). For the default build, the structure is stored
// in the PyInterpreterState structure (threads do not have their own
// structure and all share the same per-interpreter structure).
PyStats *pystats;
#endif
};

/* other API */
Expand All @@ -239,6 +248,21 @@ PyAPI_FUNC(void) PyThreadState_EnterTracing(PyThreadState *tstate);
// function is set, otherwise disable them.
PyAPI_FUNC(void) PyThreadState_LeaveTracing(PyThreadState *tstate);

#ifdef Py_STATS
#if defined(HAVE_THREAD_LOCAL) && !defined(Py_BUILD_CORE_MODULE)
extern _Py_thread_local PyThreadState *_Py_tss_tstate;

static inline PyStats*
_PyThreadState_GetStatsFast(void)
{
if (_Py_tss_tstate == NULL) {
return NULL; // no attached thread state
}
return _Py_tss_tstate->pystats;
}
#endif
#endif // Py_STATS

/* PyGILState */

/* Helper/diagnostic function - return 1 if the current thread
Expand Down
64 changes: 51 additions & 13 deletions Include/cpython/pystats.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//
// - _Py_INCREF_STAT_INC() and _Py_DECREF_STAT_INC() used by Py_INCREF()
// and Py_DECREF().
// - _Py_stats variable
// - _PyStats_GET()
//
// Functions of the sys module:
//
Expand All @@ -14,7 +14,7 @@
// - sys._stats_dump()
//
// Python must be built with ./configure --enable-pystats to define the
// Py_STATS macro.
// _PyStats_GET() macro.
//
// Define _PY_INTERPRETER macro to increment interpreter_increfs and
// interpreter_decrefs. Otherwise, increment increfs and decrefs.
Expand Down Expand Up @@ -109,6 +109,18 @@ typedef struct _gc_stats {
uint64_t objects_not_transitively_reachable;
} GCStats;

#ifdef Py_GIL_DISABLED
// stats specific to free-threaded build
typedef struct _ft_stats {
// number of times interpreter had to spin or park when trying to acquire a mutex
uint64_t mutex_sleeps;
// number of times that the QSBR mechanism polled (compute read sequence value)
uint64_t qsbr_polls;
// number of times stop-the-world mechanism was used
uint64_t world_stops;
} FTStats;
#endif

typedef struct _uop_stats {
uint64_t execution_count;
uint64_t miss;
Expand Down Expand Up @@ -173,22 +185,48 @@ typedef struct _stats {
CallStats call_stats;
ObjectStats object_stats;
OptimizationStats optimization_stats;
#ifdef Py_GIL_DISABLED
FTStats ft_stats;
#endif
RareEventStats rare_event_stats;
GCStats *gc_stats;
GCStats gc_stats[3]; // must match NUM_GENERATIONS
} PyStats;

// Export for most shared extensions
PyAPI_FUNC(PyStats *) _PyStats_GetLocal(void);

#if defined(HAVE_THREAD_LOCAL) && !defined(Py_BUILD_CORE_MODULE)
// use inline function version defined in cpython/pystate.h
static inline PyStats *_PyThreadState_GetStatsFast(void);
#define _PyStats_GET _PyThreadState_GetStatsFast
#else
#define _PyStats_GET _PyStats_GetLocal
#endif

// Export for shared extensions like 'math'
PyAPI_DATA(PyStats*) _Py_stats;
#define _Py_STATS_EXPR(expr) \
do { \
PyStats *s = _PyStats_GET(); \
if (s != NULL) { \
s->expr; \
} \
} while (0)

#define _Py_STATS_COND_EXPR(cond, expr) \
do { \
PyStats *s = _PyStats_GET(); \
if (s != NULL && (cond)) { \
s->expr; \
} \
} while (0)

#ifdef _PY_INTERPRETER
# define _Py_INCREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.interpreter_increfs++; } while (0)
# define _Py_DECREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.interpreter_decrefs++; } while (0)
# define _Py_INCREF_IMMORTAL_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.interpreter_immortal_increfs++; } while (0)
# define _Py_DECREF_IMMORTAL_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.interpreter_immortal_decrefs++; } while (0)
# define _Py_INCREF_STAT_INC() _Py_STATS_EXPR(object_stats.interpreter_increfs++)
# define _Py_DECREF_STAT_INC() _Py_STATS_EXPR(object_stats.interpreter_decrefs++)
# define _Py_INCREF_IMMORTAL_STAT_INC() _Py_STATS_EXPR(object_stats.interpreter_immortal_increfs++)
# define _Py_DECREF_IMMORTAL_STAT_INC() _Py_STATS_EXPR(object_stats.interpreter_immortal_decrefs++)
#else
# define _Py_INCREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.increfs++; } while (0)
# define _Py_DECREF_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.decrefs++; } while (0)
# define _Py_INCREF_IMMORTAL_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.immortal_increfs++; } while (0)
# define _Py_DECREF_IMMORTAL_STAT_INC() do { if (_Py_stats) _Py_stats->object_stats.immortal_decrefs++; } while (0)
# define _Py_INCREF_STAT_INC() _Py_STATS_EXPR(object_stats.increfs++)
# define _Py_DECREF_STAT_INC() _Py_STATS_EXPR(object_stats.decrefs++)
# define _Py_INCREF_IMMORTAL_STAT_INC() _Py_STATS_EXPR(object_stats.immortal_increfs++)
# define _Py_DECREF_IMMORTAL_STAT_INC() _Py_STATS_EXPR(object_stats.immortal_decrefs++)
#endif
Loading
Loading