10000 GH-112354: Initial implementation of warm up on exits and trace-stitc… · python/cpython@7b21403 · GitHub
[go: up one dir, main page]

Skip to content

Commit 7b21403

Browse files
authored
GH-112354: Initial implementation of warm up on exits and trace-stitching (GH-114142)
1 parent acda175 commit 7b21403

29 files changed

+744
-198
lines changed

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Include/internal/pycore_opcode.h generated
7777
Include/internal/pycore_opcode_metadata.h generated
7878
Include/internal/pycore_*_generated.h generated
7979
Include/internal/pycore_uop_ids.h generated
80+
Include/internal/pycore_uop_metadata.h generated
8081
Include/opcode.h generated
8182
Include/opcode_ids.h generated
8283
Include/token.h generated

Include/cpython/optimizer.h

Lines changed: 19 additions & 6 deletions
< 57AE tr class="diff-line-row">
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,28 @@ typedef struct {
3333
typedef struct {
3434
uint16_t opcode;
3535
uint16_t oparg;
36-
uint32_t target;
36+
union {
37+
uint32_t target;
38+
uint32_t exit_index;
39+
};
3740
uint64_t operand; // A cache entry
3841
} _PyUOpInstruction;
3942

43+
typedef struct _exit_data {
44+
uint32_t target;
45+
int16_t temperature;
46+
const struct _PyExecutorObject *executor;
47+
} _PyExitData;
48+
4049
typedef struct _PyExecutorObject {
4150
PyObject_VAR_HEAD
51+
const _PyUOpInstruction *trace;
4252
_PyVMData vm_data; /* Used by the VM, but opaque to the optimizer */
43-
void *jit_code;
53+
uint32_t exit_count;
54+
uint32_t code_size;
4455
size_t jit_size;
45-
_PyUOpInstruction trace[1];
56+
void *jit_code;
57+
_PyExitData exits[1];
4658
} _PyExecutorObject;
4759

4860
typedef struct _PyOptimizerObject _PyOptimizerObject;
@@ -59,6 +71,7 @@ typedef struct _PyOptimizerObject {
5971
/* These thresholds are treated as signed so do not exceed INT16_MAX
6072
* Use INT16_MAX to indicate that the optimizer should never be called */
6173
uint16_t resume_threshold;
74+
uint16_t side_threshold;
6275
uint16_t backedge_threshold;
6376
/* Data needed by the optimizer goes here, but is opaque to the VM */
6477
} _PyOptimizerObject;
@@ -73,16 +86,16 @@ PyAPI_FUNC(int) PyUnstable_Replace_Executor(PyCodeObject *code, _Py_CODEUNIT *in
7386

7487
_PyOptimizerObject *_Py_SetOptimizer(PyInterpreterState *interp, _PyOptimizerObject* optimizer);
7588

76-
PyAPI_FUNC(void) PyUnstable_SetOptimizer(_PyOptimizerObject* optimizer);
89+
PyAPI_FUNC(int) PyUnstable_SetOptimizer(_PyOptimizerObject* optimizer);
7790

7891
PyAPI_FUNC(_PyOptimizerObject *) PyUnstable_GetOptimizer(void);
7992

8093
PyAPI_FUNC(_PyExecutorObject *) PyUnstable_GetExecutor(PyCodeObject *code, int offset);
8194

8295
int
83-
_PyOptimizer_Optimize(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *start, PyObject **stack_pointer);
96+
_PyOptimizer_Optimize(struct _PyInterpreterFrame *frame, _Py_CODEUNIT *start, PyObject **stack_pointer, _PyExecutorObject **exec_ptr);
8497

85-
void _Py_ExecutorInit(_PyExecutorObject *, _PyBloomFilter *);
98+
void _Py_ExecutorInit(_PyExecutorObject *, const _PyBloomFilter *);
8699
void _Py_ExecutorClear(_PyExecutorObject *);
87100
void _Py_BloomFilter_Init(_PyBloomFilter *);
88101
void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj);

Include/cpython/pystate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ struct _ts {
212212
/* The thread's exception stack entry. (Always the last entry.) */
213213
_PyErr_StackItem exc_state;
214214

215+
PyObject *previous_executor;
216+
215217
};
216218

217219
#ifdef Py_DEBUG

Include/internal/pycore_interp.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,10 +237,13 @@ struct _is {
237237
struct callable_cache callable_cache;
238238
_PyOptimizerObject *optimizer;
239239
_PyExecutorObject *executor_list_head;
240-
/* These values are shifted and offset to speed up check in JUMP_BACKWARD */
240+
241+
/* These two values are shifted and offset to speed up check in JUMP_BACKWARD */
241242
uint32_t optimizer_resume_threshold;
242243
uint32_t optimizer_backedge_threshold;
243244

245+
uint16_t optimizer_side_threshold;
246+
244247
uint32_t next_func_version;
245248
_rare_events rare_events;
246249
PyDict_WatchCallback builtins_dict_watcher;

Include/internal/pycore_jit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ extern "C" {
1313

1414
typedef _Py_CODEUNIT *(*jit_func)(_PyInterpreterFrame *frame, PyObject **stack_pointer, PyThreadState *tstate);
1515

16-
int _PyJIT_Compile(_PyExecutorObject *executor, _PyUOpInstruction *trace, size_t length);
16+
int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length);
1717
void _PyJIT_Free(_PyExecutorObject *executor);
1818

1919
#endif // _Py_JIT

Include/internal/pycore_opcode_metadata.h

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

Include/internal/pycore_uop_ids.h

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

Include/internal/pycore_uop_metadata.h

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

Lib/test/test_frame.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,7 @@ def f():
331331
# on the *very next* allocation:
332332
gc.collect()
333333
gc.set_threshold(1, 0, 0)
334+
sys._clear_internal_caches()
334335
# Okay, so here's the nightmare scenario:
335336
# - We're tracing the resumption of a generator, which creates a new
336337
# frame object.

Lib/test/test_generated_cases.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,17 @@ def test_annotated_op(self):
794794
self.run_cases_test(input, output)
795795

796796

797+
def test_deopt_and_exit(self):
798+
input = """
799+
pure op(OP, (arg1 -- out)) {
800+
DEOPT_IF(1);
801+
EXIT_IF(1);
802+
}
803+
"""
804+
output = ""
805+
with self.assertRaises(Exception):
806+
self.run_cases_test(input, output)
807+
797808
class TestGeneratedAbstractCases(unittest.TestCase):
798809
def setUp(self) -> None:
799810
super().setUp()

Modules/_testinternalcapi.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -977,7 +977,9 @@ set_optimizer(PyObject *self, PyObject *opt)
977977
if (opt == Py_None) {
978978
opt = NULL;
979979
}
980-
PyUnstable_SetOptimizer((_PyOptimizerObject*)opt);
980+
if (PyUnstable_SetOptimizer((_PyOptimizerObject*)opt) < 0) {
981+
return NULL;
982+
}
981983
Py_RETURN_NONE;
982984
}
983985

0 commit comments

Comments
 (0)
0