xref: /aosp_15_r20/prebuilts/build-tools/common/py3-stdlib/profile.py (revision cda5da8d549138a6648c5ee6d7a49cf8f4a657be)
1*cda5da8dSAndroid Build Coastguard Worker#! /usr/bin/env python3
2*cda5da8dSAndroid Build Coastguard Worker#
3*cda5da8dSAndroid Build Coastguard Worker# Class for profiling python code. rev 1.0  6/2/94
4*cda5da8dSAndroid Build Coastguard Worker#
5*cda5da8dSAndroid Build Coastguard Worker# Written by James Roskind
6*cda5da8dSAndroid Build Coastguard Worker# Based on prior profile module by Sjoerd Mullender...
7*cda5da8dSAndroid Build Coastguard Worker#   which was hacked somewhat by: Guido van Rossum
8*cda5da8dSAndroid Build Coastguard Worker
9*cda5da8dSAndroid Build Coastguard Worker"""Class for profiling Python code."""
10*cda5da8dSAndroid Build Coastguard Worker
11*cda5da8dSAndroid Build Coastguard Worker# Copyright Disney Enterprises, Inc.  All Rights Reserved.
12*cda5da8dSAndroid Build Coastguard Worker# Licensed to PSF under a Contributor Agreement
13*cda5da8dSAndroid Build Coastguard Worker#
14*cda5da8dSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
15*cda5da8dSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
16*cda5da8dSAndroid Build Coastguard Worker# You may obtain a copy of the License at
17*cda5da8dSAndroid Build Coastguard Worker#
18*cda5da8dSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0
19*cda5da8dSAndroid Build Coastguard Worker#
20*cda5da8dSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
21*cda5da8dSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
22*cda5da8dSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
23*cda5da8dSAndroid Build Coastguard Worker# either express or implied.  See the License for the specific language
24*cda5da8dSAndroid Build Coastguard Worker# governing permissions and limitations under the License.
25*cda5da8dSAndroid Build Coastguard Worker
26*cda5da8dSAndroid Build Coastguard Worker
27*cda5da8dSAndroid Build Coastguard Workerimport io
28*cda5da8dSAndroid Build Coastguard Workerimport sys
29*cda5da8dSAndroid Build Coastguard Workerimport time
30*cda5da8dSAndroid Build Coastguard Workerimport marshal
31*cda5da8dSAndroid Build Coastguard Worker
32*cda5da8dSAndroid Build Coastguard Worker__all__ = ["run", "runctx", "Profile"]
33*cda5da8dSAndroid Build Coastguard Worker
34*cda5da8dSAndroid Build Coastguard Worker# Sample timer for use with
35*cda5da8dSAndroid Build Coastguard Worker#i_count = 0
36*cda5da8dSAndroid Build Coastguard Worker#def integer_timer():
37*cda5da8dSAndroid Build Coastguard Worker#       global i_count
38*cda5da8dSAndroid Build Coastguard Worker#       i_count = i_count + 1
39*cda5da8dSAndroid Build Coastguard Worker#       return i_count
40*cda5da8dSAndroid Build Coastguard Worker#itimes = integer_timer # replace with C coded timer returning integers
41*cda5da8dSAndroid Build Coastguard Worker
42*cda5da8dSAndroid Build Coastguard Workerclass _Utils:
43*cda5da8dSAndroid Build Coastguard Worker    """Support class for utility functions which are shared by
44*cda5da8dSAndroid Build Coastguard Worker    profile.py and cProfile.py modules.
45*cda5da8dSAndroid Build Coastguard Worker    Not supposed to be used directly.
46*cda5da8dSAndroid Build Coastguard Worker    """
47*cda5da8dSAndroid Build Coastguard Worker
48*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, profiler):
49*cda5da8dSAndroid Build Coastguard Worker        self.profiler = profiler
50*cda5da8dSAndroid Build Coastguard Worker
51*cda5da8dSAndroid Build Coastguard Worker    def run(self, statement, filename, sort):
52*cda5da8dSAndroid Build Coastguard Worker        prof = self.profiler()
53*cda5da8dSAndroid Build Coastguard Worker        try:
54*cda5da8dSAndroid Build Coastguard Worker            prof.run(statement)
55*cda5da8dSAndroid Build Coastguard Worker        except SystemExit:
56*cda5da8dSAndroid Build Coastguard Worker            pass
57*cda5da8dSAndroid Build Coastguard Worker        finally:
58*cda5da8dSAndroid Build Coastguard Worker            self._show(prof, filename, sort)
59*cda5da8dSAndroid Build Coastguard Worker
60*cda5da8dSAndroid Build Coastguard Worker    def runctx(self, statement, globals, locals, filename, sort):
61*cda5da8dSAndroid Build Coastguard Worker        prof = self.profiler()
62*cda5da8dSAndroid Build Coastguard Worker        try:
63*cda5da8dSAndroid Build Coastguard Worker            prof.runctx(statement, globals, locals)
64*cda5da8dSAndroid Build Coastguard Worker        except SystemExit:
65*cda5da8dSAndroid Build Coastguard Worker            pass
66*cda5da8dSAndroid Build Coastguard Worker        finally:
67*cda5da8dSAndroid Build Coastguard Worker            self._show(prof, filename, sort)
68*cda5da8dSAndroid Build Coastguard Worker
69*cda5da8dSAndroid Build Coastguard Worker    def _show(self, prof, filename, sort):
70*cda5da8dSAndroid Build Coastguard Worker        if filename is not None:
71*cda5da8dSAndroid Build Coastguard Worker            prof.dump_stats(filename)
72*cda5da8dSAndroid Build Coastguard Worker        else:
73*cda5da8dSAndroid Build Coastguard Worker            prof.print_stats(sort)
74*cda5da8dSAndroid Build Coastguard Worker
75*cda5da8dSAndroid Build Coastguard Worker
76*cda5da8dSAndroid Build Coastguard Worker#**************************************************************************
77*cda5da8dSAndroid Build Coastguard Worker# The following are the static member functions for the profiler class
78*cda5da8dSAndroid Build Coastguard Worker# Note that an instance of Profile() is *not* needed to call them.
79*cda5da8dSAndroid Build Coastguard Worker#**************************************************************************
80*cda5da8dSAndroid Build Coastguard Worker
81*cda5da8dSAndroid Build Coastguard Workerdef run(statement, filename=None, sort=-1):
82*cda5da8dSAndroid Build Coastguard Worker    """Run statement under profiler optionally saving results in filename
83*cda5da8dSAndroid Build Coastguard Worker
84*cda5da8dSAndroid Build Coastguard Worker    This function takes a single argument that can be passed to the
85*cda5da8dSAndroid Build Coastguard Worker    "exec" statement, and an optional file name.  In all cases this
86*cda5da8dSAndroid Build Coastguard Worker    routine attempts to "exec" its first argument and gather profiling
87*cda5da8dSAndroid Build Coastguard Worker    statistics from the execution. If no file name is present, then this
88*cda5da8dSAndroid Build Coastguard Worker    function automatically prints a simple profiling report, sorted by the
89*cda5da8dSAndroid Build Coastguard Worker    standard name string (file/line/function-name) that is presented in
90*cda5da8dSAndroid Build Coastguard Worker    each line.
91*cda5da8dSAndroid Build Coastguard Worker    """
92*cda5da8dSAndroid Build Coastguard Worker    return _Utils(Profile).run(statement, filename, sort)
93*cda5da8dSAndroid Build Coastguard Worker
94*cda5da8dSAndroid Build Coastguard Workerdef runctx(statement, globals, locals, filename=None, sort=-1):
95*cda5da8dSAndroid Build Coastguard Worker    """Run statement under profiler, supplying your own globals and locals,
96*cda5da8dSAndroid Build Coastguard Worker    optionally saving results in filename.
97*cda5da8dSAndroid Build Coastguard Worker
98*cda5da8dSAndroid Build Coastguard Worker    statement and filename have the same semantics as profile.run
99*cda5da8dSAndroid Build Coastguard Worker    """
100*cda5da8dSAndroid Build Coastguard Worker    return _Utils(Profile).runctx(statement, globals, locals, filename, sort)
101*cda5da8dSAndroid Build Coastguard Worker
102*cda5da8dSAndroid Build Coastguard Worker
103*cda5da8dSAndroid Build Coastguard Workerclass Profile:
104*cda5da8dSAndroid Build Coastguard Worker    """Profiler class.
105*cda5da8dSAndroid Build Coastguard Worker
106*cda5da8dSAndroid Build Coastguard Worker    self.cur is always a tuple.  Each such tuple corresponds to a stack
107*cda5da8dSAndroid Build Coastguard Worker    frame that is currently active (self.cur[-2]).  The following are the
108*cda5da8dSAndroid Build Coastguard Worker    definitions of its members.  We use this external "parallel stack" to
109*cda5da8dSAndroid Build Coastguard Worker    avoid contaminating the program that we are profiling. (old profiler
110*cda5da8dSAndroid Build Coastguard Worker    used to write into the frames local dictionary!!) Derived classes
111*cda5da8dSAndroid Build Coastguard Worker    can change the definition of some entries, as long as they leave
112*cda5da8dSAndroid Build Coastguard Worker    [-2:] intact (frame and previous tuple).  In case an internal error is
113*cda5da8dSAndroid Build Coastguard Worker    detected, the -3 element is used as the function name.
114*cda5da8dSAndroid Build Coastguard Worker
115*cda5da8dSAndroid Build Coastguard Worker    [ 0] = Time that needs to be charged to the parent frame's function.
116*cda5da8dSAndroid Build Coastguard Worker           It is used so that a function call will not have to access the
117*cda5da8dSAndroid Build Coastguard Worker           timing data for the parent frame.
118*cda5da8dSAndroid Build Coastguard Worker    [ 1] = Total time spent in this frame's function, excluding time in
119*cda5da8dSAndroid Build Coastguard Worker           subfunctions (this latter is tallied in cur[2]).
120*cda5da8dSAndroid Build Coastguard Worker    [ 2] = Total time spent in subfunctions, excluding time executing the
121*cda5da8dSAndroid Build Coastguard Worker           frame's function (this latter is tallied in cur[1]).
122*cda5da8dSAndroid Build Coastguard Worker    [-3] = Name of the function that corresponds to this frame.
123*cda5da8dSAndroid Build Coastguard Worker    [-2] = Actual frame that we correspond to (used to sync exception handling).
124*cda5da8dSAndroid Build Coastguard Worker    [-1] = Our parent 6-tuple (corresponds to frame.f_back).
125*cda5da8dSAndroid Build Coastguard Worker
126*cda5da8dSAndroid Build Coastguard Worker    Timing data for each function is stored as a 5-tuple in the dictionary
127*cda5da8dSAndroid Build Coastguard Worker    self.timings[].  The index is always the name stored in self.cur[-3].
128*cda5da8dSAndroid Build Coastguard Worker    The following are the definitions of the members:
129*cda5da8dSAndroid Build Coastguard Worker
130*cda5da8dSAndroid Build Coastguard Worker    [0] = The number of times this function was called, not counting direct
131*cda5da8dSAndroid Build Coastguard Worker          or indirect recursion,
132*cda5da8dSAndroid Build Coastguard Worker    [1] = Number of times this function appears on the stack, minus one
133*cda5da8dSAndroid Build Coastguard Worker    [2] = Total time spent internal to this function
134*cda5da8dSAndroid Build Coastguard Worker    [3] = Cumulative time that this function was present on the stack.  In
135*cda5da8dSAndroid Build Coastguard Worker          non-recursive functions, this is the total execution time from start
136*cda5da8dSAndroid Build Coastguard Worker          to finish of each invocation of a function, including time spent in
137*cda5da8dSAndroid Build Coastguard Worker          all subfunctions.
138*cda5da8dSAndroid Build Coastguard Worker    [4] = A dictionary indicating for each function name, the number of times
139*cda5da8dSAndroid Build Coastguard Worker          it was called by us.
140*cda5da8dSAndroid Build Coastguard Worker    """
141*cda5da8dSAndroid Build Coastguard Worker
142*cda5da8dSAndroid Build Coastguard Worker    bias = 0  # calibration constant
143*cda5da8dSAndroid Build Coastguard Worker
144*cda5da8dSAndroid Build Coastguard Worker    def __init__(self, timer=None, bias=None):
145*cda5da8dSAndroid Build Coastguard Worker        self.timings = {}
146*cda5da8dSAndroid Build Coastguard Worker        self.cur = None
147*cda5da8dSAndroid Build Coastguard Worker        self.cmd = ""
148*cda5da8dSAndroid Build Coastguard Worker        self.c_func_name = ""
149*cda5da8dSAndroid Build Coastguard Worker
150*cda5da8dSAndroid Build Coastguard Worker        if bias is None:
151*cda5da8dSAndroid Build Coastguard Worker            bias = self.bias
152*cda5da8dSAndroid Build Coastguard Worker        self.bias = bias     # Materialize in local dict for lookup speed.
153*cda5da8dSAndroid Build Coastguard Worker
154*cda5da8dSAndroid Build Coastguard Worker        if not timer:
155*cda5da8dSAndroid Build Coastguard Worker            self.timer = self.get_time = time.process_time
156*cda5da8dSAndroid Build Coastguard Worker            self.dispatcher = self.trace_dispatch_i
157*cda5da8dSAndroid Build Coastguard Worker        else:
158*cda5da8dSAndroid Build Coastguard Worker            self.timer = timer
159*cda5da8dSAndroid Build Coastguard Worker            t = self.timer() # test out timer function
160*cda5da8dSAndroid Build Coastguard Worker            try:
161*cda5da8dSAndroid Build Coastguard Worker                length = len(t)
162*cda5da8dSAndroid Build Coastguard Worker            except TypeError:
163*cda5da8dSAndroid Build Coastguard Worker                self.get_time = timer
164*cda5da8dSAndroid Build Coastguard Worker                self.dispatcher = self.trace_dispatch_i
165*cda5da8dSAndroid Build Coastguard Worker            else:
166*cda5da8dSAndroid Build Coastguard Worker                if length == 2:
167*cda5da8dSAndroid Build Coastguard Worker                    self.dispatcher = self.trace_dispatch
168*cda5da8dSAndroid Build Coastguard Worker                else:
169*cda5da8dSAndroid Build Coastguard Worker                    self.dispatcher = self.trace_dispatch_l
170*cda5da8dSAndroid Build Coastguard Worker                # This get_time() implementation needs to be defined
171*cda5da8dSAndroid Build Coastguard Worker                # here to capture the passed-in timer in the parameter
172*cda5da8dSAndroid Build Coastguard Worker                # list (for performance).  Note that we can't assume
173*cda5da8dSAndroid Build Coastguard Worker                # the timer() result contains two values in all
174*cda5da8dSAndroid Build Coastguard Worker                # cases.
175*cda5da8dSAndroid Build Coastguard Worker                def get_time_timer(timer=timer, sum=sum):
176*cda5da8dSAndroid Build Coastguard Worker                    return sum(timer())
177*cda5da8dSAndroid Build Coastguard Worker                self.get_time = get_time_timer
178*cda5da8dSAndroid Build Coastguard Worker        self.t = self.get_time()
179*cda5da8dSAndroid Build Coastguard Worker        self.simulate_call('profiler')
180*cda5da8dSAndroid Build Coastguard Worker
181*cda5da8dSAndroid Build Coastguard Worker    # Heavily optimized dispatch routine for time.process_time() timer
182*cda5da8dSAndroid Build Coastguard Worker
183*cda5da8dSAndroid Build Coastguard Worker    def trace_dispatch(self, frame, event, arg):
184*cda5da8dSAndroid Build Coastguard Worker        timer = self.timer
185*cda5da8dSAndroid Build Coastguard Worker        t = timer()
186*cda5da8dSAndroid Build Coastguard Worker        t = t[0] + t[1] - self.t - self.bias
187*cda5da8dSAndroid Build Coastguard Worker
188*cda5da8dSAndroid Build Coastguard Worker        if event == "c_call":
189*cda5da8dSAndroid Build Coastguard Worker            self.c_func_name = arg.__name__
190*cda5da8dSAndroid Build Coastguard Worker
191*cda5da8dSAndroid Build Coastguard Worker        if self.dispatch[event](self, frame,t):
192*cda5da8dSAndroid Build Coastguard Worker            t = timer()
193*cda5da8dSAndroid Build Coastguard Worker            self.t = t[0] + t[1]
194*cda5da8dSAndroid Build Coastguard Worker        else:
195*cda5da8dSAndroid Build Coastguard Worker            r = timer()
196*cda5da8dSAndroid Build Coastguard Worker            self.t = r[0] + r[1] - t # put back unrecorded delta
197*cda5da8dSAndroid Build Coastguard Worker
198*cda5da8dSAndroid Build Coastguard Worker    # Dispatch routine for best timer program (return = scalar, fastest if
199*cda5da8dSAndroid Build Coastguard Worker    # an integer but float works too -- and time.process_time() relies on that).
200*cda5da8dSAndroid Build Coastguard Worker
201*cda5da8dSAndroid Build Coastguard Worker    def trace_dispatch_i(self, frame, event, arg):
202*cda5da8dSAndroid Build Coastguard Worker        timer = self.timer
203*cda5da8dSAndroid Build Coastguard Worker        t = timer() - self.t - self.bias
204*cda5da8dSAndroid Build Coastguard Worker
205*cda5da8dSAndroid Build Coastguard Worker        if event == "c_call":
206*cda5da8dSAndroid Build Coastguard Worker            self.c_func_name = arg.__name__
207*cda5da8dSAndroid Build Coastguard Worker
208*cda5da8dSAndroid Build Coastguard Worker        if self.dispatch[event](self, frame, t):
209*cda5da8dSAndroid Build Coastguard Worker            self.t = timer()
210*cda5da8dSAndroid Build Coastguard Worker        else:
211*cda5da8dSAndroid Build Coastguard Worker            self.t = timer() - t  # put back unrecorded delta
212*cda5da8dSAndroid Build Coastguard Worker
213*cda5da8dSAndroid Build Coastguard Worker    # Dispatch routine for macintosh (timer returns time in ticks of
214*cda5da8dSAndroid Build Coastguard Worker    # 1/60th second)
215*cda5da8dSAndroid Build Coastguard Worker
216*cda5da8dSAndroid Build Coastguard Worker    def trace_dispatch_mac(self, frame, event, arg):
217*cda5da8dSAndroid Build Coastguard Worker        timer = self.timer
218*cda5da8dSAndroid Build Coastguard Worker        t = timer()/60.0 - self.t - self.bias
219*cda5da8dSAndroid Build Coastguard Worker
220*cda5da8dSAndroid Build Coastguard Worker        if event == "c_call":
221*cda5da8dSAndroid Build Coastguard Worker            self.c_func_name = arg.__name__
222*cda5da8dSAndroid Build Coastguard Worker
223*cda5da8dSAndroid Build Coastguard Worker        if self.dispatch[event](self, frame, t):
224*cda5da8dSAndroid Build Coastguard Worker            self.t = timer()/60.0
225*cda5da8dSAndroid Build Coastguard Worker        else:
226*cda5da8dSAndroid Build Coastguard Worker            self.t = timer()/60.0 - t  # put back unrecorded delta
227*cda5da8dSAndroid Build Coastguard Worker
228*cda5da8dSAndroid Build Coastguard Worker    # SLOW generic dispatch routine for timer returning lists of numbers
229*cda5da8dSAndroid Build Coastguard Worker
230*cda5da8dSAndroid Build Coastguard Worker    def trace_dispatch_l(self, frame, event, arg):
231*cda5da8dSAndroid Build Coastguard Worker        get_time = self.get_time
232*cda5da8dSAndroid Build Coastguard Worker        t = get_time() - self.t - self.bias
233*cda5da8dSAndroid Build Coastguard Worker
234*cda5da8dSAndroid Build Coastguard Worker        if event == "c_call":
235*cda5da8dSAndroid Build Coastguard Worker            self.c_func_name = arg.__name__
236*cda5da8dSAndroid Build Coastguard Worker
237*cda5da8dSAndroid Build Coastguard Worker        if self.dispatch[event](self, frame, t):
238*cda5da8dSAndroid Build Coastguard Worker            self.t = get_time()
239*cda5da8dSAndroid Build Coastguard Worker        else:
240*cda5da8dSAndroid Build Coastguard Worker            self.t = get_time() - t # put back unrecorded delta
241*cda5da8dSAndroid Build Coastguard Worker
242*cda5da8dSAndroid Build Coastguard Worker    # In the event handlers, the first 3 elements of self.cur are unpacked
243*cda5da8dSAndroid Build Coastguard Worker    # into vrbls w/ 3-letter names.  The last two characters are meant to be
244*cda5da8dSAndroid Build Coastguard Worker    # mnemonic:
245*cda5da8dSAndroid Build Coastguard Worker    #     _pt  self.cur[0] "parent time"   time to be charged to parent frame
246*cda5da8dSAndroid Build Coastguard Worker    #     _it  self.cur[1] "internal time" time spent directly in the function
247*cda5da8dSAndroid Build Coastguard Worker    #     _et  self.cur[2] "external time" time spent in subfunctions
248*cda5da8dSAndroid Build Coastguard Worker
249*cda5da8dSAndroid Build Coastguard Worker    def trace_dispatch_exception(self, frame, t):
250*cda5da8dSAndroid Build Coastguard Worker        rpt, rit, ret, rfn, rframe, rcur = self.cur
251*cda5da8dSAndroid Build Coastguard Worker        if (rframe is not frame) and rcur:
252*cda5da8dSAndroid Build Coastguard Worker            return self.trace_dispatch_return(rframe, t)
253*cda5da8dSAndroid Build Coastguard Worker        self.cur = rpt, rit+t, ret, rfn, rframe, rcur
254*cda5da8dSAndroid Build Coastguard Worker        return 1
255*cda5da8dSAndroid Build Coastguard Worker
256*cda5da8dSAndroid Build Coastguard Worker
257*cda5da8dSAndroid Build Coastguard Worker    def trace_dispatch_call(self, frame, t):
258*cda5da8dSAndroid Build Coastguard Worker        if self.cur and frame.f_back is not self.cur[-2]:
259*cda5da8dSAndroid Build Coastguard Worker            rpt, rit, ret, rfn, rframe, rcur = self.cur
260*cda5da8dSAndroid Build Coastguard Worker            if not isinstance(rframe, Profile.fake_frame):
261*cda5da8dSAndroid Build Coastguard Worker                assert rframe.f_back is frame.f_back, ("Bad call", rfn,
262*cda5da8dSAndroid Build Coastguard Worker                                                       rframe, rframe.f_back,
263*cda5da8dSAndroid Build Coastguard Worker                                                       frame, frame.f_back)
264*cda5da8dSAndroid Build Coastguard Worker                self.trace_dispatch_return(rframe, 0)
265*cda5da8dSAndroid Build Coastguard Worker                assert (self.cur is None or \
266*cda5da8dSAndroid Build Coastguard Worker                        frame.f_back is self.cur[-2]), ("Bad call",
267*cda5da8dSAndroid Build Coastguard Worker                                                        self.cur[-3])
268*cda5da8dSAndroid Build Coastguard Worker        fcode = frame.f_code
269*cda5da8dSAndroid Build Coastguard Worker        fn = (fcode.co_filename, fcode.co_firstlineno, fcode.co_name)
270*cda5da8dSAndroid Build Coastguard Worker        self.cur = (t, 0, 0, fn, frame, self.cur)
271*cda5da8dSAndroid Build Coastguard Worker        timings = self.timings
272*cda5da8dSAndroid Build Coastguard Worker        if fn in timings:
273*cda5da8dSAndroid Build Coastguard Worker            cc, ns, tt, ct, callers = timings[fn]
274*cda5da8dSAndroid Build Coastguard Worker            timings[fn] = cc, ns + 1, tt, ct, callers
275*cda5da8dSAndroid Build Coastguard Worker        else:
276*cda5da8dSAndroid Build Coastguard Worker            timings[fn] = 0, 0, 0, 0, {}
277*cda5da8dSAndroid Build Coastguard Worker        return 1
278*cda5da8dSAndroid Build Coastguard Worker
279*cda5da8dSAndroid Build Coastguard Worker    def trace_dispatch_c_call (self, frame, t):
280*cda5da8dSAndroid Build Coastguard Worker        fn = ("", 0, self.c_func_name)
281*cda5da8dSAndroid Build Coastguard Worker        self.cur = (t, 0, 0, fn, frame, self.cur)
282*cda5da8dSAndroid Build Coastguard Worker        timings = self.timings
283*cda5da8dSAndroid Build Coastguard Worker        if fn in timings:
284*cda5da8dSAndroid Build Coastguard Worker            cc, ns, tt, ct, callers = timings[fn]
285*cda5da8dSAndroid Build Coastguard Worker            timings[fn] = cc, ns+1, tt, ct, callers
286*cda5da8dSAndroid Build Coastguard Worker        else:
287*cda5da8dSAndroid Build Coastguard Worker            timings[fn] = 0, 0, 0, 0, {}
288*cda5da8dSAndroid Build Coastguard Worker        return 1
289*cda5da8dSAndroid Build Coastguard Worker
290*cda5da8dSAndroid Build Coastguard Worker    def trace_dispatch_return(self, frame, t):
291*cda5da8dSAndroid Build Coastguard Worker        if frame is not self.cur[-2]:
292*cda5da8dSAndroid Build Coastguard Worker            assert frame is self.cur[-2].f_back, ("Bad return", self.cur[-3])
293*cda5da8dSAndroid Build Coastguard Worker            self.trace_dispatch_return(self.cur[-2], 0)
294*cda5da8dSAndroid Build Coastguard Worker
295*cda5da8dSAndroid Build Coastguard Worker        # Prefix "r" means part of the Returning or exiting frame.
296*cda5da8dSAndroid Build Coastguard Worker        # Prefix "p" means part of the Previous or Parent or older frame.
297*cda5da8dSAndroid Build Coastguard Worker
298*cda5da8dSAndroid Build Coastguard Worker        rpt, rit, ret, rfn, frame, rcur = self.cur
299*cda5da8dSAndroid Build Coastguard Worker        rit = rit + t
300*cda5da8dSAndroid Build Coastguard Worker        frame_total = rit + ret
301*cda5da8dSAndroid Build Coastguard Worker
302*cda5da8dSAndroid Build Coastguard Worker        ppt, pit, pet, pfn, pframe, pcur = rcur
303*cda5da8dSAndroid Build Coastguard Worker        self.cur = ppt, pit + rpt, pet + frame_total, pfn, pframe, pcur
304*cda5da8dSAndroid Build Coastguard Worker
305*cda5da8dSAndroid Build Coastguard Worker        timings = self.timings
306*cda5da8dSAndroid Build Coastguard Worker        cc, ns, tt, ct, callers = timings[rfn]
307*cda5da8dSAndroid Build Coastguard Worker        if not ns:
308*cda5da8dSAndroid Build Coastguard Worker            # This is the only occurrence of the function on the stack.
309*cda5da8dSAndroid Build Coastguard Worker            # Else this is a (directly or indirectly) recursive call, and
310*cda5da8dSAndroid Build Coastguard Worker            # its cumulative time will get updated when the topmost call to
311*cda5da8dSAndroid Build Coastguard Worker            # it returns.
312*cda5da8dSAndroid Build Coastguard Worker            ct = ct + frame_total
313*cda5da8dSAndroid Build Coastguard Worker            cc = cc + 1
314*cda5da8dSAndroid Build Coastguard Worker
315*cda5da8dSAndroid Build Coastguard Worker        if pfn in callers:
316*cda5da8dSAndroid Build Coastguard Worker            callers[pfn] = callers[pfn] + 1  # hack: gather more
317*cda5da8dSAndroid Build Coastguard Worker            # stats such as the amount of time added to ct courtesy
318*cda5da8dSAndroid Build Coastguard Worker            # of this specific call, and the contribution to cc
319*cda5da8dSAndroid Build Coastguard Worker            # courtesy of this call.
320*cda5da8dSAndroid Build Coastguard Worker        else:
321*cda5da8dSAndroid Build Coastguard Worker            callers[pfn] = 1
322*cda5da8dSAndroid Build Coastguard Worker
323*cda5da8dSAndroid Build Coastguard Worker        timings[rfn] = cc, ns - 1, tt + rit, ct, callers
324*cda5da8dSAndroid Build Coastguard Worker
325*cda5da8dSAndroid Build Coastguard Worker        return 1
326*cda5da8dSAndroid Build Coastguard Worker
327*cda5da8dSAndroid Build Coastguard Worker
328*cda5da8dSAndroid Build Coastguard Worker    dispatch = {
329*cda5da8dSAndroid Build Coastguard Worker        "call": trace_dispatch_call,
330*cda5da8dSAndroid Build Coastguard Worker        "exception": trace_dispatch_exception,
331*cda5da8dSAndroid Build Coastguard Worker        "return": trace_dispatch_return,
332*cda5da8dSAndroid Build Coastguard Worker        "c_call": trace_dispatch_c_call,
333*cda5da8dSAndroid Build Coastguard Worker        "c_exception": trace_dispatch_return,  # the C function returned
334*cda5da8dSAndroid Build Coastguard Worker        "c_return": trace_dispatch_return,
335*cda5da8dSAndroid Build Coastguard Worker        }
336*cda5da8dSAndroid Build Coastguard Worker
337*cda5da8dSAndroid Build Coastguard Worker
338*cda5da8dSAndroid Build Coastguard Worker    # The next few functions play with self.cmd. By carefully preloading
339*cda5da8dSAndroid Build Coastguard Worker    # our parallel stack, we can force the profiled result to include
340*cda5da8dSAndroid Build Coastguard Worker    # an arbitrary string as the name of the calling function.
341*cda5da8dSAndroid Build Coastguard Worker    # We use self.cmd as that string, and the resulting stats look
342*cda5da8dSAndroid Build Coastguard Worker    # very nice :-).
343*cda5da8dSAndroid Build Coastguard Worker
344*cda5da8dSAndroid Build Coastguard Worker    def set_cmd(self, cmd):
345*cda5da8dSAndroid Build Coastguard Worker        if self.cur[-1]: return   # already set
346*cda5da8dSAndroid Build Coastguard Worker        self.cmd = cmd
347*cda5da8dSAndroid Build Coastguard Worker        self.simulate_call(cmd)
348*cda5da8dSAndroid Build Coastguard Worker
349*cda5da8dSAndroid Build Coastguard Worker    class fake_code:
350*cda5da8dSAndroid Build Coastguard Worker        def __init__(self, filename, line, name):
351*cda5da8dSAndroid Build Coastguard Worker            self.co_filename = filename
352*cda5da8dSAndroid Build Coastguard Worker            self.co_line = line
353*cda5da8dSAndroid Build Coastguard Worker            self.co_name = name
354*cda5da8dSAndroid Build Coastguard Worker            self.co_firstlineno = 0
355*cda5da8dSAndroid Build Coastguard Worker
356*cda5da8dSAndroid Build Coastguard Worker        def __repr__(self):
357*cda5da8dSAndroid Build Coastguard Worker            return repr((self.co_filename, self.co_line, self.co_name))
358*cda5da8dSAndroid Build Coastguard Worker
359*cda5da8dSAndroid Build Coastguard Worker    class fake_frame:
360*cda5da8dSAndroid Build Coastguard Worker        def __init__(self, code, prior):
361*cda5da8dSAndroid Build Coastguard Worker            self.f_code = code
362*cda5da8dSAndroid Build Coastguard Worker            self.f_back = prior
363*cda5da8dSAndroid Build Coastguard Worker
364*cda5da8dSAndroid Build Coastguard Worker    def simulate_call(self, name):
365*cda5da8dSAndroid Build Coastguard Worker        code = self.fake_code('profile', 0, name)
366*cda5da8dSAndroid Build Coastguard Worker        if self.cur:
367*cda5da8dSAndroid Build Coastguard Worker            pframe = self.cur[-2]
368*cda5da8dSAndroid Build Coastguard Worker        else:
369*cda5da8dSAndroid Build Coastguard Worker            pframe = None
370*cda5da8dSAndroid Build Coastguard Worker        frame = self.fake_frame(code, pframe)
371*cda5da8dSAndroid Build Coastguard Worker        self.dispatch['call'](self, frame, 0)
372*cda5da8dSAndroid Build Coastguard Worker
373*cda5da8dSAndroid Build Coastguard Worker    # collect stats from pending stack, including getting final
374*cda5da8dSAndroid Build Coastguard Worker    # timings for self.cmd frame.
375*cda5da8dSAndroid Build Coastguard Worker
376*cda5da8dSAndroid Build Coastguard Worker    def simulate_cmd_complete(self):
377*cda5da8dSAndroid Build Coastguard Worker        get_time = self.get_time
378*cda5da8dSAndroid Build Coastguard Worker        t = get_time() - self.t
379*cda5da8dSAndroid Build Coastguard Worker        while self.cur[-1]:
380*cda5da8dSAndroid Build Coastguard Worker            # We *can* cause assertion errors here if
381*cda5da8dSAndroid Build Coastguard Worker            # dispatch_trace_return checks for a frame match!
382*cda5da8dSAndroid Build Coastguard Worker            self.dispatch['return'](self, self.cur[-2], t)
383*cda5da8dSAndroid Build Coastguard Worker            t = 0
384*cda5da8dSAndroid Build Coastguard Worker        self.t = get_time() - t
385*cda5da8dSAndroid Build Coastguard Worker
386*cda5da8dSAndroid Build Coastguard Worker
387*cda5da8dSAndroid Build Coastguard Worker    def print_stats(self, sort=-1):
388*cda5da8dSAndroid Build Coastguard Worker        import pstats
389*cda5da8dSAndroid Build Coastguard Worker        pstats.Stats(self).strip_dirs().sort_stats(sort). \
390*cda5da8dSAndroid Build Coastguard Worker                  print_stats()
391*cda5da8dSAndroid Build Coastguard Worker
392*cda5da8dSAndroid Build Coastguard Worker    def dump_stats(self, file):
393*cda5da8dSAndroid Build Coastguard Worker        with open(file, 'wb') as f:
394*cda5da8dSAndroid Build Coastguard Worker            self.create_stats()
395*cda5da8dSAndroid Build Coastguard Worker            marshal.dump(self.stats, f)
396*cda5da8dSAndroid Build Coastguard Worker
397*cda5da8dSAndroid Build Coastguard Worker    def create_stats(self):
398*cda5da8dSAndroid Build Coastguard Worker        self.simulate_cmd_complete()
399*cda5da8dSAndroid Build Coastguard Worker        self.snapshot_stats()
400*cda5da8dSAndroid Build Coastguard Worker
401*cda5da8dSAndroid Build Coastguard Worker    def snapshot_stats(self):
402*cda5da8dSAndroid Build Coastguard Worker        self.stats = {}
403*cda5da8dSAndroid Build Coastguard Worker        for func, (cc, ns, tt, ct, callers) in self.timings.items():
404*cda5da8dSAndroid Build Coastguard Worker            callers = callers.copy()
405*cda5da8dSAndroid Build Coastguard Worker            nc = 0
406*cda5da8dSAndroid Build Coastguard Worker            for callcnt in callers.values():
407*cda5da8dSAndroid Build Coastguard Worker                nc += callcnt
408*cda5da8dSAndroid Build Coastguard Worker            self.stats[func] = cc, nc, tt, ct, callers
409*cda5da8dSAndroid Build Coastguard Worker
410*cda5da8dSAndroid Build Coastguard Worker
411*cda5da8dSAndroid Build Coastguard Worker    # The following two methods can be called by clients to use
412*cda5da8dSAndroid Build Coastguard Worker    # a profiler to profile a statement, given as a string.
413*cda5da8dSAndroid Build Coastguard Worker
414*cda5da8dSAndroid Build Coastguard Worker    def run(self, cmd):
415*cda5da8dSAndroid Build Coastguard Worker        import __main__
416*cda5da8dSAndroid Build Coastguard Worker        dict = __main__.__dict__
417*cda5da8dSAndroid Build Coastguard Worker        return self.runctx(cmd, dict, dict)
418*cda5da8dSAndroid Build Coastguard Worker
419*cda5da8dSAndroid Build Coastguard Worker    def runctx(self, cmd, globals, locals):
420*cda5da8dSAndroid Build Coastguard Worker        self.set_cmd(cmd)
421*cda5da8dSAndroid Build Coastguard Worker        sys.setprofile(self.dispatcher)
422*cda5da8dSAndroid Build Coastguard Worker        try:
423*cda5da8dSAndroid Build Coastguard Worker            exec(cmd, globals, locals)
424*cda5da8dSAndroid Build Coastguard Worker        finally:
425*cda5da8dSAndroid Build Coastguard Worker            sys.setprofile(None)
426*cda5da8dSAndroid Build Coastguard Worker        return self
427*cda5da8dSAndroid Build Coastguard Worker
428*cda5da8dSAndroid Build Coastguard Worker    # This method is more useful to profile a single function call.
429*cda5da8dSAndroid Build Coastguard Worker    def runcall(self, func, /, *args, **kw):
430*cda5da8dSAndroid Build Coastguard Worker        self.set_cmd(repr(func))
431*cda5da8dSAndroid Build Coastguard Worker        sys.setprofile(self.dispatcher)
432*cda5da8dSAndroid Build Coastguard Worker        try:
433*cda5da8dSAndroid Build Coastguard Worker            return func(*args, **kw)
434*cda5da8dSAndroid Build Coastguard Worker        finally:
435*cda5da8dSAndroid Build Coastguard Worker            sys.setprofile(None)
436*cda5da8dSAndroid Build Coastguard Worker
437*cda5da8dSAndroid Build Coastguard Worker
438*cda5da8dSAndroid Build Coastguard Worker    #******************************************************************
439*cda5da8dSAndroid Build Coastguard Worker    # The following calculates the overhead for using a profiler.  The
440*cda5da8dSAndroid Build Coastguard Worker    # problem is that it takes a fair amount of time for the profiler
441*cda5da8dSAndroid Build Coastguard Worker    # to stop the stopwatch (from the time it receives an event).
442*cda5da8dSAndroid Build Coastguard Worker    # Similarly, there is a delay from the time that the profiler
443*cda5da8dSAndroid Build Coastguard Worker    # re-starts the stopwatch before the user's code really gets to
444*cda5da8dSAndroid Build Coastguard Worker    # continue.  The following code tries to measure the difference on
445*cda5da8dSAndroid Build Coastguard Worker    # a per-event basis.
446*cda5da8dSAndroid Build Coastguard Worker    #
447*cda5da8dSAndroid Build Coastguard Worker    # Note that this difference is only significant if there are a lot of
448*cda5da8dSAndroid Build Coastguard Worker    # events, and relatively little user code per event.  For example,
449*cda5da8dSAndroid Build Coastguard Worker    # code with small functions will typically benefit from having the
450*cda5da8dSAndroid Build Coastguard Worker    # profiler calibrated for the current platform.  This *could* be
451*cda5da8dSAndroid Build Coastguard Worker    # done on the fly during init() time, but it is not worth the
452*cda5da8dSAndroid Build Coastguard Worker    # effort.  Also note that if too large a value specified, then
453*cda5da8dSAndroid Build Coastguard Worker    # execution time on some functions will actually appear as a
454*cda5da8dSAndroid Build Coastguard Worker    # negative number.  It is *normal* for some functions (with very
455*cda5da8dSAndroid Build Coastguard Worker    # low call counts) to have such negative stats, even if the
456*cda5da8dSAndroid Build Coastguard Worker    # calibration figure is "correct."
457*cda5da8dSAndroid Build Coastguard Worker    #
458*cda5da8dSAndroid Build Coastguard Worker    # One alternative to profile-time calibration adjustments (i.e.,
459*cda5da8dSAndroid Build Coastguard Worker    # adding in the magic little delta during each event) is to track
460*cda5da8dSAndroid Build Coastguard Worker    # more carefully the number of events (and cumulatively, the number
461*cda5da8dSAndroid Build Coastguard Worker    # of events during sub functions) that are seen.  If this were
462*cda5da8dSAndroid Build Coastguard Worker    # done, then the arithmetic could be done after the fact (i.e., at
463*cda5da8dSAndroid Build Coastguard Worker    # display time).  Currently, we track only call/return events.
464*cda5da8dSAndroid Build Coastguard Worker    # These values can be deduced by examining the callees and callers
465*cda5da8dSAndroid Build Coastguard Worker    # vectors for each functions.  Hence we *can* almost correct the
466*cda5da8dSAndroid Build Coastguard Worker    # internal time figure at print time (note that we currently don't
467*cda5da8dSAndroid Build Coastguard Worker    # track exception event processing counts).  Unfortunately, there
468*cda5da8dSAndroid Build Coastguard Worker    # is currently no similar information for cumulative sub-function
469*cda5da8dSAndroid Build Coastguard Worker    # time.  It would not be hard to "get all this info" at profiler
470*cda5da8dSAndroid Build Coastguard Worker    # time.  Specifically, we would have to extend the tuples to keep
471*cda5da8dSAndroid Build Coastguard Worker    # counts of this in each frame, and then extend the defs of timing
472*cda5da8dSAndroid Build Coastguard Worker    # tuples to include the significant two figures. I'm a bit fearful
473*cda5da8dSAndroid Build Coastguard Worker    # that this additional feature will slow the heavily optimized
474*cda5da8dSAndroid Build Coastguard Worker    # event/time ratio (i.e., the profiler would run slower, fur a very
475*cda5da8dSAndroid Build Coastguard Worker    # low "value added" feature.)
476*cda5da8dSAndroid Build Coastguard Worker    #**************************************************************
477*cda5da8dSAndroid Build Coastguard Worker
478*cda5da8dSAndroid Build Coastguard Worker    def calibrate(self, m, verbose=0):
479*cda5da8dSAndroid Build Coastguard Worker        if self.__class__ is not Profile:
480*cda5da8dSAndroid Build Coastguard Worker            raise TypeError("Subclasses must override .calibrate().")
481*cda5da8dSAndroid Build Coastguard Worker
482*cda5da8dSAndroid Build Coastguard Worker        saved_bias = self.bias
483*cda5da8dSAndroid Build Coastguard Worker        self.bias = 0
484*cda5da8dSAndroid Build Coastguard Worker        try:
485*cda5da8dSAndroid Build Coastguard Worker            return self._calibrate_inner(m, verbose)
486*cda5da8dSAndroid Build Coastguard Worker        finally:
487*cda5da8dSAndroid Build Coastguard Worker            self.bias = saved_bias
488*cda5da8dSAndroid Build Coastguard Worker
489*cda5da8dSAndroid Build Coastguard Worker    def _calibrate_inner(self, m, verbose):
490*cda5da8dSAndroid Build Coastguard Worker        get_time = self.get_time
491*cda5da8dSAndroid Build Coastguard Worker
492*cda5da8dSAndroid Build Coastguard Worker        # Set up a test case to be run with and without profiling.  Include
493*cda5da8dSAndroid Build Coastguard Worker        # lots of calls, because we're trying to quantify stopwatch overhead.
494*cda5da8dSAndroid Build Coastguard Worker        # Do not raise any exceptions, though, because we want to know
495*cda5da8dSAndroid Build Coastguard Worker        # exactly how many profile events are generated (one call event, +
496*cda5da8dSAndroid Build Coastguard Worker        # one return event, per Python-level call).
497*cda5da8dSAndroid Build Coastguard Worker
498*cda5da8dSAndroid Build Coastguard Worker        def f1(n):
499*cda5da8dSAndroid Build Coastguard Worker            for i in range(n):
500*cda5da8dSAndroid Build Coastguard Worker                x = 1
501*cda5da8dSAndroid Build Coastguard Worker
502*cda5da8dSAndroid Build Coastguard Worker        def f(m, f1=f1):
503*cda5da8dSAndroid Build Coastguard Worker            for i in range(m):
504*cda5da8dSAndroid Build Coastguard Worker                f1(100)
505*cda5da8dSAndroid Build Coastguard Worker
506*cda5da8dSAndroid Build Coastguard Worker        f(m)    # warm up the cache
507*cda5da8dSAndroid Build Coastguard Worker
508*cda5da8dSAndroid Build Coastguard Worker        # elapsed_noprofile <- time f(m) takes without profiling.
509*cda5da8dSAndroid Build Coastguard Worker        t0 = get_time()
510*cda5da8dSAndroid Build Coastguard Worker        f(m)
511*cda5da8dSAndroid Build Coastguard Worker        t1 = get_time()
512*cda5da8dSAndroid Build Coastguard Worker        elapsed_noprofile = t1 - t0
513*cda5da8dSAndroid Build Coastguard Worker        if verbose:
514*cda5da8dSAndroid Build Coastguard Worker            print("elapsed time without profiling =", elapsed_noprofile)
515*cda5da8dSAndroid Build Coastguard Worker
516*cda5da8dSAndroid Build Coastguard Worker        # elapsed_profile <- time f(m) takes with profiling.  The difference
517*cda5da8dSAndroid Build Coastguard Worker        # is profiling overhead, only some of which the profiler subtracts
518*cda5da8dSAndroid Build Coastguard Worker        # out on its own.
519*cda5da8dSAndroid Build Coastguard Worker        p = Profile()
520*cda5da8dSAndroid Build Coastguard Worker        t0 = get_time()
521*cda5da8dSAndroid Build Coastguard Worker        p.runctx('f(m)', globals(), locals())
522*cda5da8dSAndroid Build Coastguard Worker        t1 = get_time()
523*cda5da8dSAndroid Build Coastguard Worker        elapsed_profile = t1 - t0
524*cda5da8dSAndroid Build Coastguard Worker        if verbose:
525*cda5da8dSAndroid Build Coastguard Worker            print("elapsed time with profiling =", elapsed_profile)
526*cda5da8dSAndroid Build Coastguard Worker
527*cda5da8dSAndroid Build Coastguard Worker        # reported_time <- "CPU seconds" the profiler charged to f and f1.
528*cda5da8dSAndroid Build Coastguard Worker        total_calls = 0.0
529*cda5da8dSAndroid Build Coastguard Worker        reported_time = 0.0
530*cda5da8dSAndroid Build Coastguard Worker        for (filename, line, funcname), (cc, ns, tt, ct, callers) in \
531*cda5da8dSAndroid Build Coastguard Worker                p.timings.items():
532*cda5da8dSAndroid Build Coastguard Worker            if funcname in ("f", "f1"):
533*cda5da8dSAndroid Build Coastguard Worker                total_calls += cc
534*cda5da8dSAndroid Build Coastguard Worker                reported_time += tt
535*cda5da8dSAndroid Build Coastguard Worker
536*cda5da8dSAndroid Build Coastguard Worker        if verbose:
537*cda5da8dSAndroid Build Coastguard Worker            print("'CPU seconds' profiler reported =", reported_time)
538*cda5da8dSAndroid Build Coastguard Worker            print("total # calls =", total_calls)
539*cda5da8dSAndroid Build Coastguard Worker        if total_calls != m + 1:
540*cda5da8dSAndroid Build Coastguard Worker            raise ValueError("internal error: total calls = %d" % total_calls)
541*cda5da8dSAndroid Build Coastguard Worker
542*cda5da8dSAndroid Build Coastguard Worker        # reported_time - elapsed_noprofile = overhead the profiler wasn't
543*cda5da8dSAndroid Build Coastguard Worker        # able to measure.  Divide by twice the number of calls (since there
544*cda5da8dSAndroid Build Coastguard Worker        # are two profiler events per call in this test) to get the hidden
545*cda5da8dSAndroid Build Coastguard Worker        # overhead per event.
546*cda5da8dSAndroid Build Coastguard Worker        mean = (reported_time - elapsed_noprofile) / 2.0 / total_calls
547*cda5da8dSAndroid Build Coastguard Worker        if verbose:
548*cda5da8dSAndroid Build Coastguard Worker            print("mean stopwatch overhead per profile event =", mean)
549*cda5da8dSAndroid Build Coastguard Worker        return mean
550*cda5da8dSAndroid Build Coastguard Worker
551*cda5da8dSAndroid Build Coastguard Worker#****************************************************************************
552*cda5da8dSAndroid Build Coastguard Worker
553*cda5da8dSAndroid Build Coastguard Workerdef main():
554*cda5da8dSAndroid Build Coastguard Worker    import os
555*cda5da8dSAndroid Build Coastguard Worker    from optparse import OptionParser
556*cda5da8dSAndroid Build Coastguard Worker
557*cda5da8dSAndroid Build Coastguard Worker    usage = "profile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..."
558*cda5da8dSAndroid Build Coastguard Worker    parser = OptionParser(usage=usage)
559*cda5da8dSAndroid Build Coastguard Worker    parser.allow_interspersed_args = False
560*cda5da8dSAndroid Build Coastguard Worker    parser.add_option('-o', '--outfile', dest="outfile",
561*cda5da8dSAndroid Build Coastguard Worker        help="Save stats to <outfile>", default=None)
562*cda5da8dSAndroid Build Coastguard Worker    parser.add_option('-m', dest="module", action="store_true",
563*cda5da8dSAndroid Build Coastguard Worker        help="Profile a library module.", default=False)
564*cda5da8dSAndroid Build Coastguard Worker    parser.add_option('-s', '--sort', dest="sort",
565*cda5da8dSAndroid Build Coastguard Worker        help="Sort order when printing to stdout, based on pstats.Stats class",
566*cda5da8dSAndroid Build Coastguard Worker        default=-1)
567*cda5da8dSAndroid Build Coastguard Worker
568*cda5da8dSAndroid Build Coastguard Worker    if not sys.argv[1:]:
569*cda5da8dSAndroid Build Coastguard Worker        parser.print_usage()
570*cda5da8dSAndroid Build Coastguard Worker        sys.exit(2)
571*cda5da8dSAndroid Build Coastguard Worker
572*cda5da8dSAndroid Build Coastguard Worker    (options, args) = parser.parse_args()
573*cda5da8dSAndroid Build Coastguard Worker    sys.argv[:] = args
574*cda5da8dSAndroid Build Coastguard Worker
575*cda5da8dSAndroid Build Coastguard Worker    # The script that we're profiling may chdir, so capture the absolute path
576*cda5da8dSAndroid Build Coastguard Worker    # to the output file at startup.
577*cda5da8dSAndroid Build Coastguard Worker    if options.outfile is not None:
578*cda5da8dSAndroid Build Coastguard Worker        options.outfile = os.path.abspath(options.outfile)
579*cda5da8dSAndroid Build Coastguard Worker
580*cda5da8dSAndroid Build Coastguard Worker    if len(args) > 0:
581*cda5da8dSAndroid Build Coastguard Worker        if options.module:
582*cda5da8dSAndroid Build Coastguard Worker            import runpy
583*cda5da8dSAndroid Build Coastguard Worker            code = "run_module(modname, run_name='__main__')"
584*cda5da8dSAndroid Build Coastguard Worker            globs = {
585*cda5da8dSAndroid Build Coastguard Worker                'run_module': runpy.run_module,
586*cda5da8dSAndroid Build Coastguard Worker                'modname': args[0]
587*cda5da8dSAndroid Build Coastguard Worker            }
588*cda5da8dSAndroid Build Coastguard Worker        else:
589*cda5da8dSAndroid Build Coastguard Worker            progname = args[0]
590*cda5da8dSAndroid Build Coastguard Worker            sys.path.insert(0, os.path.dirname(progname))
591*cda5da8dSAndroid Build Coastguard Worker            with io.open_code(progname) as fp:
592*cda5da8dSAndroid Build Coastguard Worker                code = compile(fp.read(), progname, 'exec')
593*cda5da8dSAndroid Build Coastguard Worker            globs = {
594*cda5da8dSAndroid Build Coastguard Worker                '__file__': progname,
595*cda5da8dSAndroid Build Coastguard Worker                '__name__': '__main__',
596*cda5da8dSAndroid Build Coastguard Worker                '__package__': None,
597*cda5da8dSAndroid Build Coastguard Worker                '__cached__': None,
598*cda5da8dSAndroid Build Coastguard Worker            }
599*cda5da8dSAndroid Build Coastguard Worker        try:
600*cda5da8dSAndroid Build Coastguard Worker            runctx(code, globs, None, options.outfile, options.sort)
601*cda5da8dSAndroid Build Coastguard Worker        except BrokenPipeError as exc:
602*cda5da8dSAndroid Build Coastguard Worker            # Prevent "Exception ignored" during interpreter shutdown.
603*cda5da8dSAndroid Build Coastguard Worker            sys.stdout = None
604*cda5da8dSAndroid Build Coastguard Worker            sys.exit(exc.errno)
605*cda5da8dSAndroid Build Coastguard Worker    else:
606*cda5da8dSAndroid Build Coastguard Worker        parser.print_usage()
607*cda5da8dSAndroid Build Coastguard Worker    return parser
608*cda5da8dSAndroid Build Coastguard Worker
609*cda5da8dSAndroid Build Coastguard Worker# When invoked as main program, invoke the profiler on a script
610*cda5da8dSAndroid Build Coastguard Workerif __name__ == '__main__':
611*cda5da8dSAndroid Build Coastguard Worker    main()
612