From bb7a0316cc6bf5593dd710ce98f08bb45ceb1fab Mon Sep 17 00:00:00 2001 From: Elizaveta Shashkova Date: Wed, 1 Mar 2017 17:07:05 +0300 Subject: [PATCH] Updates from PyDev.Debugger: --Fix the problem with making PyDBFrame a cdef by guarding the reference borrowing from the PyFrameObject (PY-22904) --- .../pydevd_additional_thread_info_regular.py | 3 + .../pydev/_pydevd_bundle/pydevd_frame.py | 19 ++-- .../pydevd_trace_dispatch_regular.py | 15 +++- .../tests_pydevd_python/performance_check.py | 89 ++++++++++++++----- 4 files changed, 100 insertions(+), 26 deletions(-) diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_additional_thread_info_regular.py b/python/helpers/pydev/_pydevd_bundle/pydevd_additional_thread_info_regular.py index a5590627b3ba..aef74a55e3a4 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_additional_thread_info_regular.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_additional_thread_info_regular.py @@ -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 #======================================================================================================================= diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_frame.py b/python/helpers/pydev/_pydevd_bundle/pydevd_frame.py index 914baf22ac30..772e125365f4 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_frame.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_frame.py @@ -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; diff --git a/python/helpers/pydev/_pydevd_bundle/pydevd_trace_dispatch_regular.py b/python/helpers/pydev/_pydevd_bundle/pydevd_trace_dispatch_regular.py index 79d231878904..7734cc3d09fd 100644 --- a/python/helpers/pydev/_pydevd_bundle/pydevd_trace_dispatch_regular.py +++ b/python/helpers/pydev/_pydevd_bundle/pydevd_trace_dispatch_regular.py @@ -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 = self.method_object +# Py_INCREF(method_obj) +# ret = (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): diff --git a/python/helpers/pydev/tests_pydevd_python/performance_check.py b/python/helpers/pydev/tests_pydevd_python/performance_check.py index 515310a8953a..90598d622276 100644 --- a/python/helpers/pydev/tests_pydevd_python/performance_check.py +++ b/python/helpers/pydev/tests_pydevd_python/performance_check.py @@ -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,))