Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(214)

Side by Side Diff: sky/tools/webkitpy/thirdparty/coverage/collector.py

Issue 946753002: Delete a bunch of dead python code. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 """Raw data collector for Coverage."""
2
3 import sys, threading
4
5 try:
6 # Use the C extension code when we can, for speed.
7 from coverage.tracer import CTracer
8 except ImportError:
9 # Couldn't import the C extension, maybe it isn't built.
10 CTracer = None
11
12
13 class PyTracer(object):
14 """Python implementation of the raw data tracer."""
15
16 # Because of poor implementations of trace-function-manipulating tools,
17 # the Python trace function must be kept very simple. In particular, there
18 # must be only one function ever set as the trace function, both through
19 # sys.settrace, and as the return value from the trace function. Put
20 # another way, the trace function must always return itself. It cannot
21 # swap in other functions, or return None to avoid tracing a particular
22 # frame.
23 #
24 # The trace manipulator that introduced this restriction is DecoratorTools,
25 # which sets a trace function, and then later restores the pre-existing one
26 # by calling sys.settrace with a function it found in the current frame.
27 #
28 # Systems that use DecoratorTools (or similar trace manipulations) must use
29 # PyTracer to get accurate results. The command-line --timid argument is
30 # used to force the use of this tracer.
31
32 def __init__(self):
33 self.data = None
34 self.should_trace = None
35 self.should_trace_cache = None
36 self.warn = None
37 self.cur_file_data = None
38 self.last_line = 0
39 self.data_stack = []
40 self.last_exc_back = None
41 self.last_exc_firstlineno = 0
42 self.arcs = False
43
44 def _trace(self, frame, event, arg_unused):
45 """The trace function passed to sys.settrace."""
46
47 #print("trace event: %s %r @%d" % (
48 # event, frame.f_code.co_filename, frame.f_lineno))
49
50 if self.last_exc_back:
51 if frame == self.last_exc_back:
52 # Someone forgot a return event.
53 if self.arcs and self.cur_file_data:
54 pair = (self.last_line, -self.last_exc_firstlineno)
55 self.cur_file_data[pair] = None
56 self.cur_file_data, self.last_line = self.data_stack.pop()
57 self.last_exc_back = None
58
59 if event == 'call':
60 # Entering a new function context. Decide if we should trace
61 # in this file.
62 self.data_stack.append((self.cur_file_data, self.last_line))
63 filename = frame.f_code.co_filename
64 tracename = self.should_trace_cache.get(filename)
65 if tracename is None:
66 tracename = self.should_trace(filename, frame)
67 self.should_trace_cache[filename] = tracename
68 #print("called, stack is %d deep, tracename is %r" % (
69 # len(self.data_stack), tracename))
70 if tracename:
71 if tracename not in self.data:
72 self.data[tracename] = {}
73 self.cur_file_data = self.data[tracename]
74 else:
75 self.cur_file_data = None
76 # Set the last_line to -1 because the next arc will be entering a
77 # code block, indicated by (-1, n).
78 self.last_line = -1
79 elif event == 'line':
80 # Record an executed line.
81 if self.cur_file_data is not None:
82 if self.arcs:
83 #print("lin", self.last_line, frame.f_lineno)
84 self.cur_file_data[(self.last_line, frame.f_lineno)] = None
85 else:
86 #print("lin", frame.f_lineno)
87 self.cur_file_data[frame.f_lineno] = None
88 self.last_line = frame.f_lineno
89 elif event == 'return':
90 if self.arcs and self.cur_file_data:
91 first = frame.f_code.co_firstlineno
92 self.cur_file_data[(self.last_line, -first)] = None
93 # Leaving this function, pop the filename stack.
94 self.cur_file_data, self.last_line = self.data_stack.pop()
95 #print("returned, stack is %d deep" % (len(self.data_stack)))
96 elif event == 'exception':
97 #print("exc", self.last_line, frame.f_lineno)
98 self.last_exc_back = frame.f_back
99 self.last_exc_firstlineno = frame.f_code.co_firstlineno
100 return self._trace
101
102 def start(self):
103 """Start this Tracer.
104
105 Return a Python function suitable for use with sys.settrace().
106
107 """
108 sys.settrace(self._trace)
109 return self._trace
110
111 def stop(self):
112 """Stop this Tracer."""
113 if hasattr(sys, "gettrace") and self.warn:
114 if sys.gettrace() != self._trace:
115 msg = "Trace function changed, measurement is likely wrong: %r"
116 self.warn(msg % sys.gettrace())
117 sys.settrace(None)
118
119 def get_stats(self):
120 """Return a dictionary of statistics, or None."""
121 return None
122
123
124 class Collector(object):
125 """Collects trace data.
126
127 Creates a Tracer object for each thread, since they track stack
128 information. Each Tracer points to the same shared data, contributing
129 traced data points.
130
131 When the Collector is started, it creates a Tracer for the current thread,
132 and installs a function to create Tracers for each new thread started.
133 When the Collector is stopped, all active Tracers are stopped.
134
135 Threads started while the Collector is stopped will never have Tracers
136 associated with them.
137
138 """
139
140 # The stack of active Collectors. Collectors are added here when started,
141 # and popped when stopped. Collectors on the stack are paused when not
142 # the top, and resumed when they become the top again.
143 _collectors = []
144
145 def __init__(self, should_trace, timid, branch, warn):
146 """Create a collector.
147
148 `should_trace` is a function, taking a filename, and returning a
149 canonicalized filename, or False depending on whether the file should
150 be traced or not.
151
152 If `timid` is true, then a slower simpler trace function will be
153 used. This is important for some environments where manipulation of
154 tracing functions make the faster more sophisticated trace function not
155 operate properly.
156
157 If `branch` is true, then branches will be measured. This involves
158 collecting data on which statements followed each other (arcs). Use
159 `get_arc_data` to get the arc data.
160
161 `warn` is a warning function, taking a single string message argument,
162 to be used if a warning needs to be issued.
163
164 """
165 self.should_trace = should_trace
166 self.warn = warn
167 self.branch = branch
168 self.reset()
169
170 if timid:
171 # Being timid: use the simple Python trace function.
172 self._trace_class = PyTracer
173 else:
174 # Being fast: use the C Tracer if it is available, else the Python
175 # trace function.
176 self._trace_class = CTracer or PyTracer
177
178 def __repr__(self):
179 return "<Collector at 0x%x>" % id(self)
180
181 def tracer_name(self):
182 """Return the class name of the tracer we're using."""
183 return self._trace_class.__name__
184
185 def reset(self):
186 """Clear collected data, and prepare to collect more."""
187 # A dictionary mapping filenames to dicts with linenumber keys,
188 # or mapping filenames to dicts with linenumber pairs as keys.
189 self.data = {}
190
191 # A cache of the results from should_trace, the decision about whether
192 # to trace execution in a file. A dict of filename to (filename or
193 # False).
194 self.should_trace_cache = {}
195
196 # Our active Tracers.
197 self.tracers = []
198
199 def _start_tracer(self):
200 """Start a new Tracer object, and store it in self.tracers."""
201 tracer = self._trace_class()
202 tracer.data = self.data
203 tracer.arcs = self.branch
204 tracer.should_trace = self.should_trace
205 tracer.should_trace_cache = self.should_trace_cache
206 tracer.warn = self.warn
207 fn = tracer.start()
208 self.tracers.append(tracer)
209 return fn
210
211 # The trace function has to be set individually on each thread before
212 # execution begins. Ironically, the only support the threading module has
213 # for running code before the thread main is the tracing function. So we
214 # install this as a trace function, and the first time it's called, it does
215 # the real trace installation.
216
217 def _installation_trace(self, frame_unused, event_unused, arg_unused):
218 """Called on new threads, installs the real tracer."""
219 # Remove ourselves as the trace function
220 sys.settrace(None)
221 # Install the real tracer.
222 fn = self._start_tracer()
223 # Invoke the real trace function with the current event, to be sure
224 # not to lose an event.
225 if fn:
226 fn = fn(frame_unused, event_unused, arg_unused)
227 # Return the new trace function to continue tracing in this scope.
228 return fn
229
230 def start(self):
231 """Start collecting trace information."""
232 if self._collectors:
233 self._collectors[-1].pause()
234 self._collectors.append(self)
235 #print >>sys.stderr, "Started: %r" % self._collectors
236
237 # Check to see whether we had a fullcoverage tracer installed.
238 traces0 = None
239 if hasattr(sys, "gettrace"):
240 fn0 = sys.gettrace()
241 if fn0:
242 tracer0 = getattr(fn0, '__self__', None)
243 if tracer0:
244 traces0 = getattr(tracer0, 'traces', None)
245
246 # Install the tracer on this thread.
247 fn = self._start_tracer()
248
249 if traces0:
250 for args in traces0:
251 (frame, event, arg), lineno = args
252 fn(frame, event, arg, lineno=lineno)
253
254 # Install our installation tracer in threading, to jump start other
255 # threads.
256 threading.settrace(self._installation_trace)
257
258 def stop(self):
259 """Stop collecting trace information."""
260 #print >>sys.stderr, "Stopping: %r" % self._collectors
261 assert self._collectors
262 assert self._collectors[-1] is self
263
264 self.pause()
265 self.tracers = []
266
267 # Remove this Collector from the stack, and resume the one underneath
268 # (if any).
269 self._collectors.pop()
270 if self._collectors:
271 self._collectors[-1].resume()
272
273 def pause(self):
274 """Pause tracing, but be prepared to `resume`."""
275 for tracer in self.tracers:
276 tracer.stop()
277 stats = tracer.get_stats()
278 if stats:
279 print("\nCoverage.py tracer stats:")
280 for k in sorted(stats.keys()):
281 print("%16s: %s" % (k, stats[k]))
282 threading.settrace(None)
283
284 def resume(self):
285 """Resume tracing after a `pause`."""
286 for tracer in self.tracers:
287 tracer.start()
288 threading.settrace(self._installation_trace)
289
290 def get_line_data(self):
291 """Return the line data collected.
292
293 Data is { filename: { lineno: None, ...}, ...}
294
295 """
296 if self.branch:
297 # If we were measuring branches, then we have to re-build the dict
298 # to show line data.
299 line_data = {}
300 for f, arcs in self.data.items():
301 line_data[f] = ldf = {}
302 for l1, _ in list(arcs.keys()):
303 if l1:
304 ldf[l1] = None
305 return line_data
306 else:
307 return self.data
308
309 def get_arc_data(self):
310 """Return the arc data collected.
311
312 Data is { filename: { (l1, l2): None, ...}, ...}
313
314 Note that no data is collected or returned if the Collector wasn't
315 created with `branch` true.
316
317 """
318 if self.branch:
319 return self.data
320 else:
321 return {}
OLDNEW
« no previous file with comments | « sky/tools/webkitpy/thirdparty/coverage/codeunit.py ('k') | sky/tools/webkitpy/thirdparty/coverage/config.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698