Tue, 19 Jul 2016 22:20:51 +0200
Check only once if a function / method has a breakpoint.
--- a/DebugClients/Python/BreakpointWatch.py Mon Jul 18 22:12:12 2016 +0200 +++ b/DebugClients/Python/BreakpointWatch.py Tue Jul 19 22:20:51 2016 +0200 @@ -27,6 +27,7 @@ """ breaks = {} # indexed by (filename, lineno) tuple: Breakpoint breakInFile = {} # indexed by filename: [lineno] + breakInFrameCache = {} def __init__(self, filename, lineno, temporary=0, cond=None): """ @@ -53,6 +54,7 @@ lines = self.breakInFile.setdefault(filename, []) if lineno not in lines: lines.append(lineno) + self.breakInFrameCache = {} def deleteMe(self): """ @@ -91,6 +93,7 @@ bp = Breakpoint.breaks.get((filename, lineno)) if bp: bp.deleteMe() + Breakpoint.breakInFrameCache = {} @staticmethod def get_break(filename, lineno):
--- a/DebugClients/Python/DebugBase.py Mon Jul 18 22:12:12 2016 +0200 +++ b/DebugClients/Python/DebugBase.py Tue Jul 19 22:20:51 2016 +0200 @@ -278,7 +278,7 @@ return self.trace_dispatch if not (self.stop_here(frame) or - self.break_anywhere(frame) or + self.__checkBreakInFrame(frame) or Watch.watches != []): # No need to trace this function return @@ -389,6 +389,43 @@ self._fnCache[fn] = fixedName return fixedName + def __checkBreakInFrame(self, frame): + """ + Private method to check if the function / method has a line number + which is a breakpoint. + @param frame the frame object + @type frame object + @return Flag indicating a function / method with breakpoint + @rtype bool + """ + try: + return Breakpoint.breakInFrameCache[ + frame.f_globals.get('__file__'), + frame.f_code.co_firstlineno] + except KeyError: + filename = self.fix_frame_filename(frame) + if filename not in Breakpoint.breakInFile: + Breakpoint.breakInFrameCache[frame.f_globals.get('__file__'), + frame.f_code.co_firstlineno] = False + return False + lineNo = frame.f_code.co_firstlineno + lineNumbers = [lineNo] + # No need to handle special case if a lot of lines between + # (e.g. closure), because the additional lines won't cause a bp + for co_lno in frame.f_code.co_lnotab[1::2]: + lineNo += ord(co_lno) + lineNumbers.append(lineNo) + + for bp in Breakpoint.breakInFile[filename]: + if bp in lineNumbers: + Breakpoint.breakInFrameCache[ + frame.f_globals.get('__file__'), + frame.f_code.co_firstlineno] = True + return True + Breakpoint.breakInFrameCache[frame.f_globals.get('__file__'), + frame.f_code.co_firstlineno] = False + return False + def break_here(self, frame): """ Public method reimplemented from bdb.py to fix the filename from the @@ -421,20 +458,6 @@ return False - def break_anywhere(self, frame): - """ - Public method reimplemented from bdb.py to do some special things. - - These speciality is to fix the filename from the frame - (see fix_frame_filename for more info). - - @param frame the frame object - @type frame object - @return flag indicating the break status - @rtype bool - """ - return self.fix_frame_filename(frame) in Breakpoint.breakInFile - def __do_clearBreak(self, filename, lineno): """ Private method called to clear a temporary breakpoint.
--- a/DebugClients/Python3/BreakpointWatch.py Mon Jul 18 22:12:12 2016 +0200 +++ b/DebugClients/Python3/BreakpointWatch.py Tue Jul 19 22:20:51 2016 +0200 @@ -27,6 +27,7 @@ """ breaks = {} # indexed by (filename, lineno) tuple: Breakpoint breakInFile = {} # indexed by filename: [lineno] + breakInFrameCache = {} def __init__(self, filename, lineno, temporary=0, cond=None): """ @@ -53,6 +54,7 @@ lines = self.breakInFile.setdefault(filename, []) if lineno not in lines: lines.append(lineno) + self.breakInFrameCache = {} def deleteMe(self): """ @@ -91,6 +93,7 @@ bp = Breakpoint.breaks.get((filename, lineno)) if bp: bp.deleteMe() + Breakpoint.breakInFrameCache = {} @staticmethod def get_break(filename, lineno):
--- a/DebugClients/Python3/DebugBase.py Mon Jul 18 22:12:12 2016 +0200 +++ b/DebugClients/Python3/DebugBase.py Tue Jul 19 22:20:51 2016 +0200 @@ -279,7 +279,7 @@ return self.trace_dispatch if not (self.stop_here(frame) or - self.break_anywhere(frame) or + self.__checkBreakInFrame(frame) or Watch.watches != []): # No need to trace this function return @@ -409,6 +409,43 @@ self._fnCache[fn] = fixedName return fixedName + def __checkBreakInFrame(self, frame): + """ + Private method to check if the function / method has a line number + which is a breakpoint. + @param frame the frame object + @type frame object + @return Flag indicating a function / method with breakpoint + @rtype bool + """ + try: + return Breakpoint.breakInFrameCache[ + frame.f_globals.get('__file__'), + frame.f_code.co_firstlineno] + except KeyError: + filename = self.fix_frame_filename(frame) + if filename not in Breakpoint.breakInFile: + Breakpoint.breakInFrameCache[frame.f_globals.get('__file__'), + frame.f_code.co_firstlineno] = False + return False + lineNo = frame.f_code.co_firstlineno + lineNumbers = [lineNo] + # No need to handle special case if a lot of lines between + # (e.g. closure), because the additional lines won't cause a bp + for co_lno in frame.f_code.co_lnotab[1::2]: + lineNo += co_lno + lineNumbers.append(lineNo) + + for bp in Breakpoint.breakInFile[filename]: + if bp in lineNumbers: + Breakpoint.breakInFrameCache[ + frame.f_globals.get('__file__'), + frame.f_code.co_firstlineno] = True + return True + Breakpoint.breakInFrameCache[frame.f_globals.get('__file__'), + frame.f_code.co_firstlineno] = False + return False + def break_here(self, frame): """ Public method reimplemented from bdb.py to fix the filename from the @@ -441,20 +478,6 @@ return False - def break_anywhere(self, frame): - """ - Public method reimplemented from bdb.py to do some special things. - - These speciality is to fix the filename from the frame - (see fix_frame_filename for more info). - - @param frame the frame object - @param frame object - @return flag indicating the break status - @rtype bool - """ - return self.fix_frame_filename(frame) in Breakpoint.breakInFile - def __do_clearBreak(self, filename, lineno): """ Private method called to clear a temporary breakpoint.