Updates from PyDev.Debugger: --Fix the problem with making PyDBFrame a cdef by guarding the reference borrowing from the PyFrameObject (PY-22904)

This commit is contained in:
Elizaveta Shashkova
2017-03-09 15:20:48 +03:00
parent d6e8ff2e92
commit bb7a0316cc
4 changed files with 100 additions and 26 deletions
@@ -2,7 +2,10 @@ import sys
import weakref
from _pydev_imps._pydev_saved_modules import thread
from _pydevd_bundle.pydevd_constants import STATE_RUN, PYTHON_SUSPEND, dict_iter_items
# IFDEF CYTHON
# ELSE
from _pydevd_bundle.pydevd_frame import PyDBFrame
# ENDIF
#=======================================================================================================================
@@ -40,11 +40,16 @@ get_file_type = DONT_TRACE.get
#=======================================================================================================================
# PyDBFrame
#=======================================================================================================================
class PyDBFrame: # No longer cdef because object was dying when only a reference to trace_dispatch was kept (need to check alternatives).
# IFDEF CYTHON
# cdef class PyDBFrame:
# ELSE
class PyDBFrame:
'''This makes the tracing for a given frame, so, the trace_dispatch
is used initially when we enter into a new context ('call') and then
is reused for the entire context.
'''
# ENDIF
#Note: class (and not instance) attributes.
@@ -52,12 +57,16 @@ class PyDBFrame: # No longer cdef because object was dying when only a reference
#considers the user input (so, the actual result must be a join of both).
filename_to_lines_where_exceptions_are_ignored = {}
filename_to_stat_info = {}
should_skip = -1
# IFDEF CYTHON
# def __init__(self, args):
# self._args = args # In the cython version we don't need to pass the frame
# cdef tuple _args
# cdef int should_skip
# def __init__(self, tuple args):
# self._args = args # In the cython version we don't need to pass the frame
# self.should_skip = -1 # On cythonized version, put in instance.
# ELSE
should_skip = -1 # Default value in class (put in instance on set).
def __init__(self, args):
#args = main_debugger, filename, base, info, t, frame
#yeap, much faster than putting in self and then getting it from self later on
@@ -303,7 +312,7 @@ class PyDBFrame: # No longer cdef because object was dying when only a reference
traceback.print_exc()
# IFDEF CYTHON
# def trace_dispatch(self, frame, str event, arg):
# cpdef trace_dispatch(self, frame, str event, arg):
# cdef str filename;
# cdef bint is_exception_event;
# cdef bint has_exception_breakpoints;
@@ -7,9 +7,10 @@ from _pydevd_bundle.pydevd_dont_trace_files import DONT_TRACE
from _pydevd_bundle.pydevd_kill_all_pydevd_threads import kill_all_pydev_threads
from pydevd_file_utils import get_abs_path_real_path_and_base_from_frame, NORM_PATHS_AND_BASE_CONTAINER
from _pydevd_bundle.pydevd_tracing import SetTrace
# IFDEF CYTHON
# # In Cython, PyDBAdditionalThreadInfo is bundled in the file.
# from cpython.object cimport PyObject
# from cpython.ref cimport Py_INCREF, Py_XDECREF
# ELSE
from _pydevd_bundle.pydevd_additional_thread_info import PyDBAdditionalThreadInfo
# ENDIF
@@ -46,6 +47,18 @@ def trace_dispatch(py_db, frame, event, arg):
return thread_tracer.__call__(frame, event, arg)
# IFDEF CYTHON
# cdef class SafeCallWrapper:
# cdef method_object
# def __init__(self, method_object):
# self.method_object = method_object
# def __call__(self, *args):
# #Cannot use 'self' once inside the delegate call since we are borrowing the self reference f_trace field
# #in the frame, and that reference might get destroyed by set trace on frame and parents
# cdef PyObject* method_obj = <PyObject*> self.method_object
# Py_INCREF(<object>method_obj)
# ret = (<object>method_obj)(*args)
# Py_XDECREF (method_obj)
# return SafeCallWrapper(ret) if ret is not None else None
# cdef class ThreadTracer:
# cdef public tuple _args;
# def __init__(self, tuple args):
@@ -82,6 +82,30 @@ class WriterThreadPerformance4(PerformanceWriterThread):
self.write_make_initial_run()
self.finished_ok = True
class WriterThreadPerformance5(PerformanceWriterThread):
TEST_FILE = debugger_unittest._get_debugger_test_file('_performance_2.py')
BENCHMARK_NAME = 'global_scope_1_with_breakpoint'
def run(self):
self.start_socket()
self.write_add_breakpoint(23, None)
self.write_make_initial_run()
self.finished_ok = True
class WriterThreadPerformance6(PerformanceWriterThread):
TEST_FILE = debugger_unittest._get_debugger_test_file('_performance_3.py')
BENCHMARK_NAME = 'global_scope_2_with_breakpoint'
def run(self):
self.start_socket()
self.write_add_breakpoint(17, None)
self.write_make_initial_run()
self.finished_ok = True
class CheckDebuggerPerformance(debugger_unittest.DebuggerRunner):
@@ -95,13 +119,19 @@ class CheckDebuggerPerformance(debugger_unittest.DebuggerRunner):
return float(time_taken)
def obtain_results(self, writer_thread_class):
time_when_debugged = self._get_time_from_result(self.check_case(writer_thread_class))
runs = 5
all_times = []
for _ in range(runs):
all_times.append(self._get_time_from_result(self.check_case(writer_thread_class)))
print('partial for: %s: %.3fs' % (writer_thread_class.BENCHMARK_NAME, all_times[-1]))
all_times.remove(min(all_times))
all_times.remove(max(all_times))
time_when_debugged = sum(all_times) / float(len(all_times))
args = self.get_command_line()
args.append(writer_thread_class.TEST_FILE)
regular_time = self._get_time_from_result(self.run_process(args, writer_thread=None))
simple_trace_time = self._get_time_from_result(self.run_process(args+['--regular-trace'], writer_thread=None))
print(writer_thread_class.BENCHMARK_NAME, time_when_debugged, regular_time, simple_trace_time)
# regular_time = self._get_time_from_result(self.run_process(args, writer_thread=None))
# simple_trace_time = self._get_time_from_result(self.run_process(args+['--regular-trace'], writer_thread=None))
if 'SPEEDTIN_AUTHORIZATION_KEY' in os.environ:
@@ -133,43 +163,62 @@ class CheckDebuggerPerformance(debugger_unittest.DebuggerRunner):
commit_id, branch, commit_date = api.git_commit_id_branch_and_date_from_path(pydevd.__file__)
api.add_benchmark(benchmark_name)
api.add_measurement(
benchmark_name,
value=time_when_debugged,
version=version,
released=False,
branch=branch,
commit_id=commit_id,
commit_date=commit_date,
benchmark_name,
value=time_when_debugged,
version=version,
released=False,
branch=branch,
commit_id=commit_id,
commit_date=commit_date,
)
api.commit()
return '%s: %.3fs ' % (writer_thread_class.BENCHMARK_NAME, time_when_debugged)
def check_performance1(self):
self.obtain_results(WriterThreadPerformance1)
return self.obtain_results(WriterThreadPerformance1)
def check_performance2(self):
self.obtain_results(WriterThreadPerformance2)
return self.obtain_results(WriterThreadPerformance2)
def check_performance3(self):
self.obtain_results(WriterThreadPerformance3)
return self.obtain_results(WriterThreadPerformance3)
def check_performance4(self):
self.obtain_results(WriterThreadPerformance4)
return self.obtain_results(WriterThreadPerformance4)
def check_performance5(self):
return self.obtain_results(WriterThreadPerformance5)
def check_performance6(self):
return self.obtain_results(WriterThreadPerformance6)
if __name__ == '__main__':
debugger_unittest.SHOW_WRITES_AND_READS = False
debugger_unittest.SHOW_OTHER_DEBUG_INFO = False
debugger_unittest.SHOW_STDOUT = False
import time
start_time = time.time()
msgs = []
for check in (
# CHECK_BASELINE, -- Checks against the version checked out at X:\PyDev.Debugger.baseline.
CHECK_REGULAR,
CHECK_CYTHON
):
PerformanceWriterThread.CHECK = check
print('Checking: %s' % (check,))
msgs.append('Checking: %s' % (check,))
check_debugger_performance = CheckDebuggerPerformance()
check_debugger_performance.check_performance1()
check_debugger_performance.check_performance2()
check_debugger_performance.check_performance3()
check_debugger_performance.check_performance4()
msgs.append(check_debugger_performance.check_performance1())
msgs.append(check_debugger_performance.check_performance2())
msgs.append(check_debugger_performance.check_performance3())
msgs.append(check_debugger_performance.check_performance4())
msgs.append(check_debugger_performance.check_performance5())
msgs.append(check_debugger_performance.check_performance6())
for msg in msgs:
print(msg)
print('TotalTime for profile: %.2fs' % (time.time()-start_time,))