mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
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:
@@ -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,))
|
||||
|
||||
Reference in New Issue
Block a user