~bzr-pqm/bzr/bzr.dev

1724.2.4 by John Arbash Meinel
Move the custom importers into a separate module
1
# Copyright (C) 2006 by Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1724.2.7 by John Arbash Meinel
It seems you cannot override __builtins__.__import__ in a sub-module.
17
"""A custom importer and regex compiler which logs time spent."""
1724.2.4 by John Arbash Meinel
Move the custom importers into a separate module
18
19
import os
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
20
import pprint
1724.2.7 by John Arbash Meinel
It seems you cannot override __builtins__.__import__ in a sub-module.
21
import sre
1724.2.4 by John Arbash Meinel
Move the custom importers into a separate module
22
import sys
23
import time
1724.2.7 by John Arbash Meinel
It seems you cannot override __builtins__.__import__ in a sub-module.
24
25
26
import_logfile = sys.stderr
27
compile_logfile = sys.stderr
1724.2.4 by John Arbash Meinel
Move the custom importers into a separate module
28
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
29
30
_parent_stack = []
31
_total_stack = {}
32
_info = {}
33
_cur_id = 0
34
35
36
def stack_add(name, frame_name, frame_lineno, scope_name=None):
37
    """Start a new record on the stack"""
38
    global _cur_id
39
    _cur_id += 1
40
    this_stack = (_cur_id, name)
41
42
    if _parent_stack:
43
        _total_stack[_parent_stack[-1]].append(this_stack)
44
    _total_stack[this_stack] = []
45
    _parent_stack.append(this_stack)
46
    _info[this_stack] = [len(_parent_stack)-1, frame_name, frame_lineno, scope_name]
47
48
    return this_stack
49
50
51
def stack_finish(this, cost):
52
    """Finish a given entry, and record its cost in time"""
53
    global _parent_stack
54
55
    if  _parent_stack[-1] != this:
56
        # This should only happen if there is a bug
57
        # (used to happen if an import failed)
58
        if this not in _parent_stack:
59
            import_logfile.write('could not find %s in callstat: %s\n'
60
                                % (this, pprint.pformat(_parent_stack)))
61
        else:
62
            idx = _parent_stack.index(this)
63
            import_logfile.write('stripping off extra children: %s\n'
64
                                % (_parent_stack[idx:],))
65
            _parent_stack = _parent_stack[:idx]
66
    else:
67
        _parent_stack.pop()
68
    _info[this].append(cost)
69
70
1724.2.10 by John Arbash Meinel
More layout work
71
def log_stack_info(out_file, sorted=True):
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
72
    # Find all of the roots with import = 0
1724.2.9 by John Arbash Meinel
change layout to be easier to mentally parse.
73
    out_file.write('cum   inline name\t\t\tscope\t\t\tframe\n')
1724.2.10 by John Arbash Meinel
More layout work
74
    todo = [(value[-1], key) for key,value in _info.iteritems() if value[0] == 0]
75
76
    if sorted:
77
        todo.sort()
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
78
79
    while todo:
1724.2.10 by John Arbash Meinel
More layout work
80
        cum_time, cur = todo.pop()
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
81
        children = _total_stack[cur]
82
1724.2.10 by John Arbash Meinel
More layout work
83
        c_times = []
84
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
85
        info = _info[cur]
86
        # Compute the module time by removing the children times
87
        mod_time = info[-1]
88
        for child in children:
89
            c_info = _info[child]
90
            mod_time -= c_info[-1]
1724.2.10 by John Arbash Meinel
More layout work
91
            c_times.append((c_info[-1], child))
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
92
93
        scope_name = info[3]
94
        if scope_name is None:
1724.2.10 by John Arbash Meinel
More layout work
95
            txt = '%-62s' % (cur[1][:64],)
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
96
        else:
1724.2.10 by John Arbash Meinel
More layout work
97
            txt = '%-27s\tfor %-24s' % (cur[1], scope_name)
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
98
        # indent, cum_time, mod_time, name,
99
        # scope_name, frame_name, frame_lineno
1724.2.9 by John Arbash Meinel
change layout to be easier to mentally parse.
100
        out_file.write('%5.1f %5.1f %s %s\t@ %s:%d\n'
101
            % (info[-1]*1000., mod_time*1000., '+'*info[0], 
102
               txt, info[1], info[2]))
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
103
1724.2.10 by John Arbash Meinel
More layout work
104
        if sorted:
105
            c_times.sort()
106
        else:
107
            c_times.reverse()
108
        todo.extend(c_times)
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
109
110
1724.2.4 by John Arbash Meinel
Move the custom importers into a separate module
111
_real_import = __import__
112
1724.2.7 by John Arbash Meinel
It seems you cannot override __builtins__.__import__ in a sub-module.
113
def timed_import(name, globals, locals, fromlist):
1724.2.4 by John Arbash Meinel
Move the custom importers into a separate module
114
    """Wrap around standard importer to log import time"""
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
115
1724.2.7 by John Arbash Meinel
It seems you cannot override __builtins__.__import__ in a sub-module.
116
    if import_logfile is None:
1724.2.4 by John Arbash Meinel
Move the custom importers into a separate module
117
        return _real_import(name, globals, locals, fromlist)
118
119
    scope_name = globals.get('__name__', None)
120
    if scope_name is None:
121
        scope_name = globals.get('__file__', None)
122
    if scope_name is None:
123
        scope_name = globals.keys()
124
    else:
125
        # Trim out paths before bzrlib
126
        loc = scope_name.find('bzrlib')
127
        if loc != -1:
128
            scope_name = scope_name[loc:]
129
        # For stdlib, trim out early paths
130
        loc = scope_name.find('python2.4')
131
        if loc != -1:
132
            scope_name = scope_name[loc:]
133
134
    # Figure out the frame that is doing the importing
135
    frame = sys._getframe(1)
136
    frame_name = frame.f_globals.get('__name__', '<unknown>')
137
    extra = ''
138
    cur_frame = 1
139
    if frame_name.endswith('demandload'):
140
        # If this was demandloaded, we have 3 frames to ignore
141
        extra = ' (demandload)'
142
        frame = sys._getframe(4)
143
        cur_frame = 4
144
        frame_name = frame.f_globals.get('__name__', '<unknown>')
145
    frame_lineno = frame.f_lineno
146
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
147
    this = stack_add(name+extra, frame_name, frame_lineno, scope_name)
148
149
    tstart = time.time()
150
    try:
151
        # Do the import
152
        mod = _real_import(name, globals, locals, fromlist)
153
    finally:
154
        tload = time.time()-tstart
155
        stack_finish(this, tload)
156
1724.2.4 by John Arbash Meinel
Move the custom importers into a separate module
157
    return mod
158
159
160
_real_compile = sre._compile
161
1724.2.7 by John Arbash Meinel
It seems you cannot override __builtins__.__import__ in a sub-module.
162
def timed_compile(*args, **kwargs):
1724.2.4 by John Arbash Meinel
Move the custom importers into a separate module
163
    """Log how long it takes to compile a regex"""
1724.2.7 by John Arbash Meinel
It seems you cannot override __builtins__.__import__ in a sub-module.
164
    if compile_logfile is None:
1724.2.4 by John Arbash Meinel
Move the custom importers into a separate module
165
        return _real_compile(*args, **kwargs)
166
167
    # And who is requesting this?
168
    frame = sys._getframe(2)
169
    frame_name = frame.f_globals.get('__name__', '<unknown>')
170
    frame_lineno = frame.f_lineno
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
171
1724.2.9 by John Arbash Meinel
change layout to be easier to mentally parse.
172
    this = stack_add(repr(args[0]), frame_name, frame_lineno)
1724.2.8 by John Arbash Meinel
New --profile-imports output which puts parents before children.
173
174
    tstart = time.time()
175
    try:
176
        # Measure the compile time
177
        comp = _real_compile(*args, **kwargs)
178
    finally:
179
        tcompile = time.time() - tstart
180
        stack_finish(this, tcompile)
181
1724.2.4 by John Arbash Meinel
Move the custom importers into a separate module
182
    return comp