| Home | Trees | Indices | Help |
|
|---|
|
|
1 """SCons.Debug
2
3 Code for debugging SCons internal things. Shouldn't be
4 needed by most users. Quick shortcuts:
5
6 from SCons.Debug import caller_trace
7 caller_trace()
8
9 """
10
11 #
12 # Copyright (c) 2001 - 2019 The SCons Foundation
13 #
14 # Permission is hereby granted, free of charge, to any person obtaining
15 # a copy of this software and associated documentation files (the
16 # "Software"), to deal in the Software without restriction, including
17 # without limitation the rights to use, copy, modify, merge, publish,
18 # distribute, sublicense, and/or sell copies of the Software, and to
19 # permit persons to whom the Software is furnished to do so, subject to
20 # the following conditions:
21 #
22 # The above copyright notice and this permission notice shall be included
23 # in all copies or substantial portions of the Software.
24 #
25 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
26 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
27 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #
33
34 __revision__ = "src/engine/SCons/Debug.py 72ae09dc35ac2626f8ff711d8c4b30b6138e08e3 2019-08-08 14:50:06 bdeegan"
35
36 import os
37 import sys
38 import time
39 import weakref
40 import inspect
41
42 # Global variable that gets set to 'True' by the Main script,
43 # when the creation of class instances should get tracked.
44 track_instances = False
45 # List of currently tracked classes
46 tracked_classes = {}
47
49 if name is None:
50 name = instance.__class__.__name__
51 if name not in tracked_classes:
52 tracked_classes[name] = []
53 if hasattr(instance, '__dict__'):
54 tracked_classes[name].append(weakref.ref(instance))
55 else:
56 # weakref doesn't seem to work when the instance
57 # contains only slots...
58 tracked_classes[name].append(instance)
59
65
67 classnames = string_to_classes(classes)
68 return [(cn, len(tracked_classes[cn])) for cn in classnames]
69
71 for classname in string_to_classes(classes):
72 file.write("%s: %d\n" % (classname, len(tracked_classes[classname])))
73
75 for classname in string_to_classes(classes):
76 file.write('\n%s:\n' % classname)
77 for ref in tracked_classes[classname]:
78 if inspect.isclass(ref):
79 obj = ref()
80 else:
81 obj = ref
82 if obj is not None:
83 file.write(' %s\n' % repr(obj))
84
86 for classname in string_to_classes(classes):
87 file.write('\n%s:\n' % classname)
88 for ref in tracked_classes[classname]:
89 obj = ref()
90 if obj is not None:
91 file.write(' %s:\n' % obj)
92 for key, value in obj.__dict__.items():
93 file.write(' %20s : %s\n' % (key, value))
94
95
96
97 if sys.platform[:5] == "linux":
98 # Linux doesn't actually support memory usage stats from getrusage().
100 with open('/proc/self/stat') as f:
101 mstr = f.read()
102 mstr = mstr.split()[22]
103 return int(mstr)
104 elif sys.platform[:6] == 'darwin':
105 #TODO really get memory stats for OS X
108 else:
109 try:
110 import resource
111 except ImportError:
112 try:
113 import win32process
114 import win32api
115 except ImportError:
118 else:
120 process_handle = win32api.GetCurrentProcess()
121 memory_info = win32process.GetProcessMemoryInfo( process_handle )
122 return memory_info['PeakWorkingSetSize']
123 else:
127
128 # returns caller's stack
130 import traceback
131 tb = traceback.extract_stack()
132 # strip itself and the caller from the output
133 tb = tb[:-2]
134 result = []
135 for back in tb:
136 # (filename, line number, function name, text)
137 key = back[:3]
138 result.append('%s:%d(%s)' % func_shorten(key))
139 return result
140
141 caller_bases = {}
142 caller_dicts = {}
143
145 """
146 Trace caller stack and save info into global dicts, which
147 are printed automatically at the end of SCons execution.
148 """
149 global caller_bases, caller_dicts
150 import traceback
151 tb = traceback.extract_stack(limit=3+back)
152 tb.reverse()
153 callee = tb[1][:3]
154 caller_bases[callee] = caller_bases.get(callee, 0) + 1
155 for caller in tb[2:]:
156 caller = callee + caller[:3]
157 try:
158 entry = caller_dicts[callee]
159 except KeyError:
160 caller_dicts[callee] = entry = {}
161 entry[caller] = entry.get(caller, 0) + 1
162 callee = caller
163
164 # print a single caller and its callers, if any
166 leader = ' '*level
167 for v,c in sorted([(-v,c) for c,v in caller_dicts[key].items()]):
168 file.write("%s %6d %s:%d(%s)\n" % ((leader,-v) + func_shorten(c[-3:])))
169 if c in caller_dicts:
170 _dump_one_caller(c, file, level+1)
171
172 # print each call tree
174 for k in sorted(caller_bases.keys()):
175 file.write("Callers of %s:%d(%s), %d calls:\n"
176 % (func_shorten(k) + (caller_bases[k],)))
177 _dump_one_caller(k, file)
178
179 shorten_list = [
180 ( '/scons/SCons/', 1),
181 ( '/src/engine/SCons/', 1),
182 ( '/usr/lib/python', 0),
183 ]
184
185 if os.sep != '/':
186 shorten_list = [(t[0].replace('/', os.sep), t[1]) for t in shorten_list]
187
189 f = func_tuple[0]
190 for t in shorten_list:
191 i = f.find(t[0])
192 if i >= 0:
193 if t[1]:
194 i = i + len(t[0])
195 return (f[i:],)+func_tuple[1:]
196 return func_tuple
197
198
199 TraceFP = {}
200 if sys.platform == 'win32':
201 TraceDefault = 'con'
202 else:
203 TraceDefault = '/dev/tty'
204
205 TimeStampDefault = None
206 StartTime = time.time()
207 PreviousTime = StartTime
208
210 """Write a trace message to a file. Whenever a file is specified,
211 it becomes the default for the next call to Trace()."""
212 global TraceDefault
213 global TimeStampDefault
214 global PreviousTime
215 if file is None:
216 file = TraceDefault
217 else:
218 TraceDefault = file
219 if tstamp is None:
220 tstamp = TimeStampDefault
221 else:
222 TimeStampDefault = tstamp
223 try:
224 fp = TraceFP[file]
225 except KeyError:
226 try:
227 fp = TraceFP[file] = open(file, mode)
228 except TypeError:
229 # Assume we were passed an open file pointer.
230 fp = file
231 if tstamp:
232 now = time.time()
233 fp.write('%8.4f %8.4f: ' % (now - StartTime, now - PreviousTime))
234 PreviousTime = now
235 fp.write(msg)
236 fp.flush()
237 fp.close()
238
239 # Local Variables:
240 # tab-width:4
241 # indent-tabs-mode:nil
242 # End:
243 # vim: set expandtab tabstop=4 shiftwidth=4:
244
| Home | Trees | Indices | Help |
|
|---|
| Generated by Epydoc 3.0.1 on Thu Aug 8 14:51:07 2019 | http://epydoc.sourceforge.net |