Don't canonic the filename any more and cache it. debugger speed

Fri, 01 Jul 2016 21:54:07 +0200

author
T.Rzepka <Tobias.Rzepka@gmail.com>
date
Fri, 01 Jul 2016 21:54:07 +0200
branch
debugger speed
changeset 5007
e2fa12bb0f53
parent 5006
82e91d2f59a1
child 5012
be693f11da53

Don't canonic the filename any more and cache it.

DebugClients/Python/DebugBase.py file | annotate | diff | comparison | revisions
DebugClients/Python3/DebugBase.py file | annotate | diff | comparison | revisions
--- a/DebugClients/Python/DebugBase.py	Sun Jun 26 21:29:18 2016 +0200
+++ b/DebugClients/Python/DebugBase.py	Fri Jul 01 21:54:07 2016 +0200
@@ -55,6 +55,9 @@
     pathsToSkip = ('<', os.path.dirname(__file__), bdb.__file__[:-1])
     filesToSkip = {}
 
+    # cache for fixed file names
+    _fnCache = {}
+
     def __init__(self, dbgClient):
         """
         Constructor
@@ -357,19 +360,28 @@
         code over a network... This logic deals with that.
         
         @param frame the frame object
-        @return fixed up file name (string)
+        @type frame object
+        @return fixed up file name
+        @rtype str
         """
         # get module name from __file__
-        if '__file__' in frame.f_globals and \
-           frame.f_globals['__file__'] and \
-           frame.f_globals['__file__'] == frame.f_code.co_filename:
-            root, ext = os.path.splitext(frame.f_globals['__file__'])
-            if ext == '.pyc' or ext == '.py' or ext == '.pyo':
-                fixedName = root + '.py'
-                if os.path.exists(fixedName):
-                    return fixedName
-
-        return frame.f_code.co_filename
+        fn = frame.f_globals.get('__file__')
+        try:
+            return self._fnCache[fn]
+        except KeyError:
+            if fn and fn != frame.f_code.co_filename:
+                absFilename = os.path.abspath(fn)
+                if absFilename.endswith(('.pyc', '.pyo')):
+                    fixedName = absFilename[:-1]
+                    if not os.path.exists(fixedName):
+                        fixedName = absFilename
+                else:
+                    fixedName = absFilename
+            else:
+                fixedName = frame.f_code.co_filename
+            # update cache
+            self._fnCache[fn] = fixedName
+            return fixedName
 
     def set_watch(self, cond, temporary=0):
         """
@@ -495,7 +507,7 @@
         @param frame the frame object
         @return flag indicating the break status (boolean)
         """
-        filename = self.canonic(self.fix_frame_filename(frame))
+        filename = self.fix_frame_filename(frame)
         if filename not in self.breaks and "Watch" not in self.breaks:
             return 0
         
@@ -532,9 +544,32 @@
         @return flag indicating the break status (boolean)
         """
         return \
-            self.canonic(self.fix_frame_filename(frame)) in self.breaks or \
+            self.fix_frame_filename(frame) in self.breaks or \
             ("Watch" in self.breaks and self.breaks["Watch"])
 
+    def set_break(self, filename, lineno, temporary=0, cond=None,
+                  funcname=None):
+        """
+        Public method reimplemented from bdb.py to normalize the filename and
+        set as a breakpoint.
+        
+        @param filename the filename where a breakpoint is set
+        @type str
+        @param lineno the line number of the breakpoint
+        @type int
+        @keyparam temporary flag to indicate a temporary breakpoint
+        @type int
+        @keyparam cond Python expression which dynamically enables this bp
+        @type str
+        @keyparam funcname name of the function (unused)
+        @type str or None
+        """
+        filename = os.path.abspath(filename)
+        list = self.breaks.setdefault(filename, [])
+        if lineno not in list:
+            list.append(lineno)
+        bdb.Breakpoint(filename, lineno, temporary, cond, funcname)
+
     def get_break(self, filename, lineno):
         """
         Public method reimplemented from bdb.py to get the first breakpoint of
@@ -543,15 +578,33 @@
         Because eric6 supports only one breakpoint per line, this overwritten
         method will return this one and only breakpoint.
         
-        @param filename the filename of the bp to retrieve (string)
-        @param lineno the linenumber of the bp to retrieve (integer)
+        @param filename the filename of the bp to retrieve
+        @type str
+        @param lineno the linenumber of the bp to retrieve
+        @type int
         @return breakpoint or None, if there is no bp
+        @rtype breakpoint object or None
+        """
+        return (lineno in self.breaks.get(filename, []) and
+                bdb.Breakpoint.bplist[filename, lineno][0] or None)
+    
+    def clear_break(self, filename, lineno):
         """
-        filename = self.canonic(filename)
-        return filename in self.breaks and \
-            lineno in self.breaks[filename] and \
-            bdb.Breakpoint.bplist[filename, lineno][0] or None
-    
+        Public method reimplemented from bdb.py to clear a breakpoint.
+        
+        @param filename the filename of the bp to retrieve
+        @type str
+        @param lineno the linenumber of the bp to retrieve
+        @type int
+        """
+        if (filename, lineno) not in bdb.Breakpoint.bplist:
+            return
+        # If there's only one bp in the list for that file,line
+        # pair, then remove the breaks entry
+        for bp in bdb.Breakpoint.bplist[filename, lineno][:]:
+            bp.deleteMe()
+        self._prune_breaks(filename, lineno)
+
     def __do_clear(self, filename, lineno):
         """
         Private method called to clear a temporary breakpoint.
@@ -812,9 +865,10 @@
 
     def tracePythonLibs(self, enable):
         """
-        Public methode to update the settings to trace into Python libraries.
+        Public method to update the settings to trace into Python libraries.
         
-        @param enable let's debug into Python libraries (int)
+        @param enable flag to debug into Python libraries
+        @type int
         """
         pathsToSkip = list(self.pathsToSkip)
         # don't trace into Python library?
@@ -837,7 +891,9 @@
         debugger that are called from the application being debugged.
         
         @param frame the frame object
+        @type frame object
         @return flag indicating whether the debugger should skip this frame
+        @rtype bool
         """
         try:
             return self.filesToSkip[frame.f_code.co_filename]
--- a/DebugClients/Python3/DebugBase.py	Sun Jun 26 21:29:18 2016 +0200
+++ b/DebugClients/Python3/DebugBase.py	Fri Jul 01 21:54:07 2016 +0200
@@ -56,6 +56,9 @@
     pathsToSkip = ('<', os.path.dirname(__file__), bdb.__file__[:-1])
     filesToSkip = {}
 
+    # cache for fixed file names
+    _fnCache = {}
+
     def __init__(self, dbgClient):
         """
         Constructor
@@ -378,23 +381,28 @@
         code over a network... This logic deals with that.
         
         @param frame the frame object
-        @return fixed up file name (string)
+        @type frame object
+        @return fixed up file name
+        @rtype str
         """
         # get module name from __file__
-        if '__file__' in frame.f_globals and \
-           frame.f_globals['__file__'] and \
-           frame.f_globals['__file__'] == frame.f_code.co_filename:
-            root, ext = os.path.splitext(frame.f_globals['__file__'])
-            if ext in ['.pyc', '.py', '.py3', '.pyo']:
-                fixedName = root + '.py'
-                if os.path.exists(fixedName):
-                    return fixedName
-                
-                fixedName = root + '.py3'
-                if os.path.exists(fixedName):
-                    return fixedName
-
-        return frame.f_code.co_filename
+        fn = frame.f_globals.get('__file__')
+        try:
+            return self._fnCache[fn]
+        except KeyError:
+            if fn and fn != frame.f_code.co_filename:
+                absFilename = os.path.abspath(fn)
+                if absFilename.endswith(('.pyc', '.pyo')):
+                    fixedName = absFilename[:-1]
+                    if not os.path.exists(fixedName):
+                        fixedName = absFilename
+                else:
+                    fixedName = absFilename
+            else:
+                fixedName = frame.f_code.co_filename
+            # update cache
+            self._fnCache[fn] = fixedName
+            return fixedName
 
     def set_watch(self, cond, temporary=False):
         """
@@ -521,7 +529,7 @@
         @param frame the frame object
         @return flag indicating the break status (boolean)
         """
-        filename = self.canonic(self.fix_frame_filename(frame))
+        filename = self.fix_frame_filename(frame)
         if filename not in self.breaks and "Watch" not in self.breaks:
             return False
         
@@ -563,9 +571,32 @@
         @return flag indicating the break status (boolean)
         """
         return \
-            self.canonic(self.fix_frame_filename(frame)) in self.breaks or \
+            self.fix_frame_filename(frame) in self.breaks or \
             ("Watch" in self.breaks and self.breaks["Watch"])
 
+    def set_break(self, filename, lineno, temporary=0, cond=None,
+                  funcname=None):
+        """
+        Public method reimplemented from bdb.py to normalize the filename and
+        set as a breakpoint.
+        
+        @param filename the filename where a breakpoint is set
+        @type str
+        @param lineno the line number of the breakpoint
+        @type int
+        @keyparam temporary flag to indicate a temporary breakpoint
+        @type int
+        @keyparam cond Python expression which dynamically enables this bp
+        @type str
+        @keyparam funcname name of the function (unused)
+        @type str or None
+        """
+        filename = os.path.abspath(filename)
+        list = self.breaks.setdefault(filename, [])
+        if lineno not in list:
+            list.append(lineno)
+        bdb.Breakpoint(filename, lineno, temporary, cond, funcname)
+
     def get_break(self, filename, lineno):
         """
         Public method reimplemented from bdb.py to get the first breakpoint of
@@ -574,15 +605,33 @@
         Because eric6 supports only one breakpoint per line, this overwritten
         method will return this one and only breakpoint.
         
-        @param filename the filename of the bp to retrieve (string)
-        @param lineno the linenumber of the bp to retrieve (integer)
+        @param filename the filename of the bp to retrieve
+        @type str
+        @param lineno the linenumber of the bp to retrieve
+        @type int
         @return breakpoint or None, if there is no bp
+        @rtype breakpoint object or None
+        """
+        return (lineno in self.breaks.get(filename, []) and
+                bdb.Breakpoint.bplist[filename, lineno][0] or None)
+    
+    def clear_break(self, filename, lineno):
         """
-        filename = self.canonic(filename)
-        return filename in self.breaks and \
-            lineno in self.breaks[filename] and \
-            bdb.Breakpoint.bplist[filename, lineno][0] or None
-    
+        Public method reimplemented from bdb.py to clear a breakpoint.
+        
+        @param filename the filename of the bp to retrieve
+        @type str
+        @param lineno the linenumber of the bp to retrieve
+        @type int
+        """
+        if (filename, lineno) not in bdb.Breakpoint.bplist:
+            return
+        # If there's only one bp in the list for that file,line
+        # pair, then remove the breaks entry
+        for bp in bdb.Breakpoint.bplist[filename, lineno][:]:
+            bp.deleteMe()
+        self._prune_breaks(filename, lineno)
+
     def __do_clear(self, filename, lineno):
         """
         Private method called to clear a temporary breakpoint.
@@ -861,9 +910,10 @@
 
     def tracePythonLibs(self, enable):
         """
-        Public methode to update the settings to trace into Python libraries.
+        Public method to update the settings to trace into Python libraries.
         
-        @param enable let's debug into Python libraries (int)
+        @param enable flag to debug into Python libraries
+        @type int
         """
         pathsToSkip = list(self.pathsToSkip)
         # don't trace into Python library?
@@ -886,7 +936,9 @@
         debugger that are called from the application being debugged.
         
         @param frame the frame object
+        @type frame object
         @return flag indicating whether the debugger should skip this frame
+        @rtype bool
         """
         try:
             return self.filesToSkip[frame.f_code.co_filename]

eric ide

mercurial