Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

GH-113710: Add a "globals to constants" pass#114592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
markshannon merged 16 commits intopython:mainfromfaster-cpython:globals-to-constants
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from1 commit
Commits
Show all changes
16 commits
Select commitHold shift + click to select a range
3941620
Change optimizer API to provide more information
markshannonJan 18, 2024
665cc58
Add new uops for optimizing globals
markshannonJan 18, 2024
9d9bc24
Optimize LOAD_GLOBAL specializations in tier 2
markshannonJan 18, 2024
24b3533
Fix handling of call stack in trace generator
markshannonJan 18, 2024
35a92cc
Get globals to const pass working
markshannonJan 18, 2024
8c699a3
Minor tidying
markshannonJan 18, 2024
28dbecd
Merge branch 'main' into globals-to-constants
markshannonJan 18, 2024
99e38ca
Merge builtin watchers and limit re-optimizations
markshannonJan 19, 2024
e0eaea9
Add braces
markshannonJan 19, 2024
d3a2590
Use a few bits in the dict version tag to track deoptimizations
markshannonJan 19, 2024
b3f2418
Address review comments
markshannonFeb 1, 2024
0798207
Merge branch 'main' into globals-to-constants
markshannonFeb 1, 2024
e65dcf2
Tolerate default optimizer being called
markshannonFeb 2, 2024
f763e37
Fix compiler warning
markshannonFeb 2, 2024
5bdac7a
Reduce modification limits a bit.
markshannonFeb 2, 2024
3dc8907
Merge branch 'main' into globals-to-constants
markshannonFeb 2, 2024
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
PrevPrevious commit
NextNext commit
Get globals to const pass working
  • Loading branch information
@markshannon
markshannon committedJan 18, 2024
commit35a92cccd3aaabf0e86734bbcdc6e0c3ff7eb8c3
3 changes: 2 additions & 1 deletionInclude/internal/pycore_optimizer.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,7 +9,8 @@ extern "C" {
#endif

int _Py_uop_analyze_and_optimize(_PyInterpreterFrame *frame,
_PyUOpInstruction *trace, int trace_len, int curr_stackentries);
_PyUOpInstruction *trace, int trace_len, int curr_stackentries,
_PyBloomFilter *dependencies);

extern PyTypeObject _PyCounterExecutor_Type;
extern PyTypeObject _PyCounterOptimizer_Type;
Expand Down
28 changes: 14 additions & 14 deletionsLib/test/test_capi/test_watchers.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -52,14 +52,6 @@ def test_set_existing_item(self):
d["foo"] = "baz"
self.assert_events(["mod:foo:baz"])

def test_clone(self):
d = {}
d2 = {"foo": "bar"}
with self.watcher() as wid:
self.watch(wid, d)
d.update(d2)
self.assert_events(["clone"])

def test_no_event_if_not_watched(self):
d = {}
with self.watcher() as wid:
Expand All@@ -80,6 +72,14 @@ def test_pop(self):
d.pop("foo")
self.assert_events(["del:foo"])

def test_clone(self):
d = {}
d2 = {"foo": "bar"}
with self.watcher() as wid:
self.watch(wid, d)
d.update(d2)
self.assert_events(["clone"])

def test_clear(self):
d = {"foo": "bar"}
with self.watcher() as wid:
Expand DownExpand Up@@ -151,8 +151,8 @@ def test_watch_out_of_range_watcher_id(self):

def test_watch_unassigned_watcher_id(self):
d = {}
with self.assertRaisesRegex(ValueError, r"No dict watcher set for ID1"):
self.watch(1, d)
with self.assertRaisesRegex(ValueError, r"No dict watcher set for ID3"):
self.watch(3, d)

def test_unwatch_non_dict(self):
with self.watcher() as wid:
Expand All@@ -168,8 +168,8 @@ def test_unwatch_out_of_range_watcher_id(self):

def test_unwatch_unassigned_watcher_id(self):
d = {}
with self.assertRaisesRegex(ValueError, r"No dict watcher set for ID1"):
self.unwatch(1, d)
with self.assertRaisesRegex(ValueError, r"No dict watcher set for ID3"):
self.unwatch(3, d)

def test_clear_out_of_range_watcher_id(self):
with self.assertRaisesRegex(ValueError, r"Invalid dict watcher ID -1"):
Expand All@@ -178,8 +178,8 @@ def test_clear_out_of_range_watcher_id(self):
self.clear_watcher(8) # DICT_MAX_WATCHERS = 8

def test_clear_unassigned_watcher_id(self):
with self.assertRaisesRegex(ValueError, r"No dict watcher set for ID1"):
self.clear_watcher(1)
with self.assertRaisesRegex(ValueError, r"No dict watcher set for ID3"):
self.clear_watcher(3)


class TestTypeWatchers(unittest.TestCase):
Expand Down
4 changes: 2 additions & 2 deletionsModules/_testcapi/watchers.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,8 +15,8 @@ module _testcapi
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6361033e795369fc]*/

// Test dict watching
static PyObject *g_dict_watch_events;
static int g_dict_watchers_installed;
static PyObject *g_dict_watch_events = NULL;
static int g_dict_watchers_installed = 0;

static int
dict_watch_callback(PyDict_WatchEvent event,
Expand Down
3 changes: 2 additions & 1 deletionObjects/dictobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -5975,7 +5975,8 @@ PyDict_AddWatcher(PyDict_WatchCallback callback)
{
PyInterpreterState *interp = _PyInterpreterState_GET();

for (int i = 0; i < DICT_MAX_WATCHERS; i++) {
/* Start at 2, as 0 and 1 as reserved for CPython */
for (int i = 2; i < DICT_MAX_WATCHERS; i++) {
if (!interp->dict_state.watchers[i]) {
interp->dict_state.watchers[i] = callback;
return i;
Expand Down
7 changes: 4 additions & 3 deletionsPython/optimizer.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -817,9 +817,10 @@ uop_optimize(
OPT_STAT_INC(traces_created);
char *uop_optimize = Py_GETENV("PYTHONUOPSOPTIMIZE");
if (uop_optimize == NULL || *uop_optimize > '0') {
err = _Py_uop_analyze_and_optimize(frame, buffer, UOP_MAX_TRACE_LENGTH, curr_stackentries);
if (err < 0) {
return -1;
err = _Py_uop_analyze_and_optimize(frame, buffer,
UOP_MAX_TRACE_LENGTH, curr_stackentries, &dependencies);
if (err <= 0) {
return err;
}
}
_PyExecutorObject *executor = make_executor_from_uops(buffer, &dependencies);
Expand Down
47 changes: 25 additions & 22 deletionsPython/optimizer_analysis.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,7 +43,6 @@ global_to_const(_PyUOpInstruction *inst, PyObject *obj)
PyDictObject *dict = (PyDictObject *)obj;
assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE);
PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys);
assert(inst->operand < dict->ma_used);
assert(inst->operand <= UINT16_MAX);
PyObject *res = entries[inst->operand].me_value;
if (res == NULL) {
Expand All@@ -59,19 +58,19 @@ global_to_const(_PyUOpInstruction *inst, PyObject *obj)
}

static int
check_globals_version(_PyUOpInstruction *inst, PyObject *obj)
incorrect_keys(_PyUOpInstruction *inst, PyObject *obj)
{
if (!PyDict_CheckExact(obj)) {
return-1;
return 1;
}
PyDictObject *dict = (PyDictObject *)obj;
if (dict->ma_keys->dk_version != inst->operand) {
return-1;
return 1;
}
return 0;
}

staticvoid
staticint
remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
int buffer_size, _PyBloomFilter *dependencies)
{
Expand DownExpand Up@@ -104,12 +103,12 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
int opcode = inst->opcode;
switch(opcode) {
case _GUARD_BUILTINS_VERSION:
if (check_globals_version(inst, builtins)) {
continue;
if (incorrect_keys(inst, builtins)) {
return 0;
}
if ((builtins_watched & 1) == 0) {
PyDict_Watch(0, builtins);
builtins_watched = 1;
builtins_watched|= 1;
}
if (builtins_checked & 1) {
buffer[pc].opcode = NOP;
Expand All@@ -121,8 +120,8 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
}
break;
case _GUARD_GLOBALS_VERSION:
if (check_globals_version(inst, globals)) {
continue;
if (incorrect_keys(inst, globals)) {
return 0;
}
if ((globals_watched & 1) == 0) {
PyDict_Watch(1, globals);
Expand All@@ -139,25 +138,26 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
}
break;
case _LOAD_GLOBAL_BUILTINS:
if (globals_checked & builtins_checked & globals_watched & builtins_watched & 1) {
global_to_const(inst, builtins);
}
assert(globals_checked & builtins_checked & globals_watched & builtins_watched & 1);
global_to_const(inst, builtins);
break;
case _LOAD_GLOBAL_MODULE:
if (globals_checked & globals_watched & 1) {
global_to_const(inst, globals);
}
assert(globals_checked & globals_watched & 1);
global_to_const(inst, globals);
break;
case _JUMP_TO_TOP:
case _EXIT_TRACE:
goto done;
return 1;
case _PUSH_FRAME:
{
globals_checked <<= 1;
globals_watched <<= 1;
builtins_checked <<= 1;
builtins_watched <<= 1;
PyFunctionObject *func = (PyFunctionObject *)buffer[pc].operand;
if (func == NULL) {
return 1;
}
assert(PyFunction_Check(func));
globals = func->func_globals;
builtins = func->func_builtins;
Expand All@@ -175,8 +175,7 @@ remove_globals(_PyInterpreterFrame *frame, _PyUOpInstruction *buffer,
break;
}
}
done:
return;
return 0;
}

static void
Expand DownExpand Up@@ -266,11 +265,15 @@ _Py_uop_analyze_and_optimize(
_PyInterpreterFrame *frame,
_PyUOpInstruction *buffer,
int buffer_size,
int curr_stacklen
int curr_stacklen,
_PyBloomFilter *dependencies
)
{
remove_globals(frame, buffer, buffer_size, dependencies);
int err = remove_globals(frame, buffer, buffer_size, dependencies);
if (err <= 0) {
return err;
}
peephole_opt(frame, buffer, buffer_size);
remove_unneeded_uops(buffer, buffer_size);
return0;
return1;
}

[8]ページ先頭

©2009-2026 Movatter.jp