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