~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to profile_imports.py

  • Committer: Patch Queue Manager
  • Date: 2015-12-17 18:39:00 UTC
  • mfrom: (6606.1.2 fix-float)
  • Revision ID: pqm@pqm.ubuntu.com-20151217183900-0719du2uv1kwu3lc
(vila) Inline testtools private method to fix an issue in xenial (the
 private implementation has changed in an backward incompatible way).
 (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 by Canonical Ltd
 
1
# Copyright (C) 2006, 2008, 2009, 2010 by Canonical Ltd
2
2
# Written by John Arbash Meinel <john@arbash-meinel.com>
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
13
13
#
14
14
# You should have received a copy of the GNU General Public License
15
15
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
 
18
18
"""A custom importer and regex compiler which logs time spent."""
19
19
 
20
 
import sre
21
20
import sys
22
21
import time
23
22
 
24
23
 
 
24
import re
 
25
 
 
26
 
25
27
_parent_stack = []
26
28
_total_stack = {}
27
29
_info = {}
28
30
_cur_id = 0
 
31
_timer = time.time
 
32
if sys.platform == 'win32':
 
33
    _timer = time.clock
29
34
 
30
35
 
31
36
def stack_add(name, frame_name, frame_lineno, scope_name=None):
55
60
 
56
61
def log_stack_info(out_file, sorted=True, hide_fast=True):
57
62
    # Find all of the roots with import = 0
58
 
    out_file.write(' cum  inline name\t\t\t\t\t\tframe\n')
 
63
    out_file.write('%5s %5s %-40s @ %s:%s\n'
 
64
        % ('cum', 'inline', 'name', 'file', 'line'))
59
65
    todo = [(value[-1], key) for key,value in _info.iteritems() if value[0] == 0]
60
66
 
61
67
    if sorted:
80
86
 
81
87
        # indent, cum_time, mod_time, name,
82
88
        # scope_name, frame_name, frame_lineno
83
 
        out_file.write('%5.1f %5.1f %s %-35s\t@ %s:%d\n'
84
 
            % (info[-1]*1000., mod_time*1000., '+'*info[0], 
85
 
               cur[1][:40], info[1], info[2]))
 
89
        out_file.write('%5.1f %5.1f %-40s @ %s:%d\n'
 
90
            % (info[-1]*1000., mod_time*1000.,
 
91
               ('+'*info[0] + cur[1]),
 
92
               info[1], info[2]))
86
93
 
87
94
        if sorted:
88
95
            c_times.sort()
93
100
 
94
101
_real_import = __import__
95
102
 
96
 
def timed_import(name, globals, locals, fromlist):
 
103
def timed_import(name, globals=None, locals=None, fromlist=None, level=None):
97
104
    """Wrap around standard importer to log import time"""
 
105
    # normally there are 4, but if this is called as __import__ eg by
 
106
    # /usr/lib/python2.6/email/__init__.py then there may be only one
 
107
    # parameter
 
108
    # level is only passed by python2.6
98
109
 
99
 
    scope_name = globals.get('__name__', None)
100
 
    if scope_name is None:
101
 
        scope_name = globals.get('__file__', None)
102
 
    if scope_name is None:
103
 
        scope_name = globals.keys()
 
110
    if globals is None:
 
111
        # can't determine the scope name afaics; we could peek up the stack to
 
112
        # see where this is being called from, but it should be a rare case.
 
113
        scope_name = None
104
114
    else:
105
 
        # Trim out paths before bzrlib
106
 
        loc = scope_name.find('bzrlib')
107
 
        if loc != -1:
108
 
            scope_name = scope_name[loc:]
109
 
        # For stdlib, trim out early paths
110
 
        loc = scope_name.find('python2.4')
111
 
        if loc != -1:
112
 
            scope_name = scope_name[loc:]
 
115
        scope_name = globals.get('__name__', None)
 
116
        if scope_name is None:
 
117
            scope_name = globals.get('__file__', None)
 
118
        if scope_name is None:
 
119
            scope_name = globals.keys()
 
120
        else:
 
121
            # Trim out paths before bzrlib
 
122
            loc = scope_name.find('bzrlib')
 
123
            if loc != -1:
 
124
                scope_name = scope_name[loc:]
 
125
            # For stdlib, trim out early paths
 
126
            loc = scope_name.find('python2.4')
 
127
            if loc != -1:
 
128
                scope_name = scope_name[loc:]
113
129
 
114
130
    # Figure out the frame that is doing the importing
115
131
    frame = sys._getframe(1)
116
132
    frame_name = frame.f_globals.get('__name__', '<unknown>')
117
133
    extra = ''
118
 
    cur_frame = 1
119
134
    if frame_name.endswith('demandload'):
120
135
        # If this was demandloaded, we have 3 frames to ignore
121
 
        extra = ' (demandload)'
122
 
        frame = sys._getframe(4)
123
 
        cur_frame = 4
124
 
        frame_name = frame.f_globals.get('__name__', '<unknown>')
 
136
        extra = '(demandload) '
 
137
        frame = sys._getframe(4)
 
138
        frame_name = frame.f_globals.get('__name__', '<unknown>')
 
139
    elif frame_name.endswith('lazy_import'):
 
140
        # If this was lazily imported, we have 3 frames to ignore
 
141
        extra = '[l] '
 
142
        frame = sys._getframe(4)
 
143
        frame_name = frame.f_globals.get('__name__', '<unknown>')
 
144
    if fromlist:
 
145
        extra += ' [%s]' % (', '.join(map(str, fromlist)),)
125
146
    frame_lineno = frame.f_lineno
126
147
 
127
 
    this = stack_add(name+extra, frame_name, frame_lineno, scope_name)
 
148
    this = stack_add(extra + name, frame_name, frame_lineno, scope_name)
128
149
 
129
 
    tstart = time.time()
 
150
    tstart = _timer()
130
151
    try:
131
152
        # Do the import
132
153
        mod = _real_import(name, globals, locals, fromlist)
133
154
    finally:
134
 
        tload = time.time()-tstart
 
155
        tload = _timer()-tstart
135
156
        stack_finish(this, tload)
136
157
 
137
158
    return mod
138
159
 
139
160
 
140
 
_real_compile = sre._compile
 
161
_real_compile = re._compile
 
162
 
141
163
 
142
164
def timed_compile(*args, **kwargs):
143
165
    """Log how long it takes to compile a regex"""
145
167
    # And who is requesting this?
146
168
    frame = sys._getframe(2)
147
169
    frame_name = frame.f_globals.get('__name__', '<unknown>')
 
170
 
 
171
    extra = ''
 
172
    if frame_name.endswith('lazy_regex'):
 
173
        # If this was lazily compiled, we have 3 more frames to ignore
 
174
        extra = '[l] '
 
175
        frame = sys._getframe(5)
 
176
        frame_name = frame.f_globals.get('__name__', '<unknown>')
148
177
    frame_lineno = frame.f_lineno
149
 
 
150
 
    this = stack_add(repr(args[0]), frame_name, frame_lineno)
151
 
 
152
 
    tstart = time.time()
 
178
    this = stack_add(extra+repr(args[0]), frame_name, frame_lineno)
 
179
 
 
180
    tstart = _timer()
153
181
    try:
154
182
        # Measure the compile time
155
183
        comp = _real_compile(*args, **kwargs)
156
184
    finally:
157
 
        tcompile = time.time() - tstart
 
185
        tcompile = _timer() - tstart
158
186
        stack_finish(this, tcompile)
159
187
 
160
188
    return comp
163
191
def install():
164
192
    """Install the hooks for measuring import and regex compile time."""
165
193
    __builtins__['__import__'] = timed_import
166
 
    sre._compile = timed_compile
 
194
    re._compile = timed_compile
167
195
 
168
196
 
169
197
def uninstall():
170
198
    """Remove the import and regex compile timing hooks."""
171
199
    __builtins__['__import__'] = _real_import
172
 
    sre._compile = _real_compile
 
200
    re._compile = _real_compile
173
201