Skip to content

Commit

Permalink
gh-103845: Remove line & instruction instrumentations before adding t…
Browse files Browse the repository at this point in the history
…hem back (GH-103851)
  • Loading branch information
gaogaotiantian committed May 3, 2023
1 parent 0a5cd98 commit bcea36f
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 8 deletions.
36 changes: 36 additions & 0 deletions Lib/test/test_monitoring.py
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,42 @@ def func3():
('instruction', 'func3', 34),
('line', 'check_events', 11)])

def test_with_restart(self):
def func1():
line1 = 1
line2 = 2
line3 = 3

self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [
('line', 'check_events', 10),
('line', 'func1', 1),
('instruction', 'func1', 2),
('instruction', 'func1', 4),
('line', 'func1', 2),
('instruction', 'func1', 6),
('instruction', 'func1', 8),
('line', 'func1', 3),
('instruction', 'func1', 10),
('instruction', 'func1', 12),
('instruction', 'func1', 14),
('line', 'check_events', 11)])

sys.monitoring.restart_events()

self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [
('line', 'check_events', 10),
('line', 'func1', 1),
('instruction', 'func1', 2),
('instruction', 'func1', 4),
('line', 'func1', 2),
('instruction', 'func1', 6),
('instruction', 'func1', 8),
('line', 'func1', 3),
('instruction', 'func1', 10),
('instruction', 'func1', 12),
('instruction', 'func1', 14),
('line', 'check_events', 11)])

class TestInstallIncrementallly(MonitoringTestBase, unittest.TestCase):

def check_events(self, func, must_include, tool=TEST_TOOL, recorders=(ExceptionRecorder,)):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove both line and instruction instrumentation before adding new ones for monitoring, to avoid newly added instrumentation being removed immediately.
41 changes: 33 additions & 8 deletions Python/instrumentation.c
Original file line number Diff line number Diff line change
Expand Up @@ -1477,25 +1477,25 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp)
}
}
}
uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE];

// GH-103845: We need to remove both the line and instruction instrumentation before
// adding new ones, otherwise we may remove the newly added instrumentation.

uint8_t removed_line_tools = removed_events.tools[PY_MONITORING_EVENT_LINE];
if (new_line_tools | removed_line_tools) {
uint8_t removed_per_instruction_tools = removed_events.tools[PY_MONITORING_EVENT_INSTRUCTION];

if (removed_line_tools) {
_PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines;
for (int i = code->_co_firsttraceable; i < code_len;) {
if (line_data[i].original_opcode) {
if (removed_line_tools) {
remove_line_tools(code, i, removed_line_tools);
}
if (new_line_tools) {
add_line_tools(code, i, new_line_tools);
}
}
i += instruction_length(code, i);
}
}
uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION];
uint8_t removed_per_instruction_tools = removed_events.tools[PY_MONITORING_EVENT_INSTRUCTION];
if (new_per_instruction_tools | removed_per_instruction_tools) {
if (removed_per_instruction_tools) {
for (int i = code->_co_firsttraceable; i < code_len;) {
int opcode = _Py_GetBaseOpcode(code, i);
if (opcode == RESUME || opcode == END_FOR) {
Expand All @@ -1505,6 +1505,31 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp)
if (removed_per_instruction_tools) {
remove_per_instruction_tools(code, i, removed_per_instruction_tools);
}
i += instruction_length(code, i);
}
}

uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE];
uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION];

if (new_line_tools) {
_PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines;
for (int i = code->_co_firsttraceable; i < code_len;) {
if (line_data[i].original_opcode) {
if (new_line_tools) {
add_line_tools(code, i, new_line_tools);
}
}
i += instruction_length(code, i);
}
}
if (new_per_instruction_tools) {
for (int i = code->_co_firsttraceable; i < code_len;) {
int opcode = _Py_GetBaseOpcode(code, i);
if (opcode == RESUME || opcode == END_FOR) {
i += instruction_length(code, i);
continue;
}
if (new_per_instruction_tools) {
add_per_instruction_tools(code, i, new_per_instruction_tools);
}
Expand Down

0 comments on commit bcea36f

Please sign in to comment.