Coverage for /pythoncovmergedfiles/medio/medio/usr/lib/python3.9/cProfile.py: 18%

115 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-25 06:05 +0000

1#! /usr/bin/env python3 

2 

3"""Python interface for the 'lsprof' profiler. 

4 Compatible with the 'profile' module. 

5""" 

6 

7__all__ = ["run", "runctx", "Profile"] 

8 

9import _lsprof 

10import profile as _pyprofile 

11 

12# ____________________________________________________________ 

13# Simple interface 

14 

15def run(statement, filename=None, sort=-1): 

16 return _pyprofile._Utils(Profile).run(statement, filename, sort) 

17 

18def runctx(statement, globals, locals, filename=None, sort=-1): 

19 return _pyprofile._Utils(Profile).runctx(statement, globals, locals, 

20 filename, sort) 

21 

22run.__doc__ = _pyprofile.run.__doc__ 

23runctx.__doc__ = _pyprofile.runctx.__doc__ 

24 

25# ____________________________________________________________ 

26 

27class Profile(_lsprof.Profiler): 

28 """Profile(timer=None, timeunit=None, subcalls=True, builtins=True) 

29 

30 Builds a profiler object using the specified timer function. 

31 The default timer is a fast built-in one based on real time. 

32 For custom timer functions returning integers, timeunit can 

33 be a float specifying a scale (i.e. how long each integer unit 

34 is, in seconds). 

35 """ 

36 

37 # Most of the functionality is in the base class. 

38 # This subclass only adds convenient and backward-compatible methods. 

39 

40 def print_stats(self, sort=-1): 

41 import pstats 

42 pstats.Stats(self).strip_dirs().sort_stats(sort).print_stats() 

43 

44 def dump_stats(self, file): 

45 import marshal 

46 with open(file, 'wb') as f: 

47 self.create_stats() 

48 marshal.dump(self.stats, f) 

49 

50 def create_stats(self): 

51 self.disable() 

52 self.snapshot_stats() 

53 

54 def snapshot_stats(self): 

55 entries = self.getstats() 

56 self.stats = {} 

57 callersdicts = {} 

58 # call information 

59 for entry in entries: 

60 func = label(entry.code) 

61 nc = entry.callcount # ncalls column of pstats (before '/') 

62 cc = nc - entry.reccallcount # ncalls column of pstats (after '/') 

63 tt = entry.inlinetime # tottime column of pstats 

64 ct = entry.totaltime # cumtime column of pstats 

65 callers = {} 

66 callersdicts[id(entry.code)] = callers 

67 self.stats[func] = cc, nc, tt, ct, callers 

68 # subcall information 

69 for entry in entries: 

70 if entry.calls: 

71 func = label(entry.code) 

72 for subentry in entry.calls: 

73 try: 

74 callers = callersdicts[id(subentry.code)] 

75 except KeyError: 

76 continue 

77 nc = subentry.callcount 

78 cc = nc - subentry.reccallcount 

79 tt = subentry.inlinetime 

80 ct = subentry.totaltime 

81 if func in callers: 

82 prev = callers[func] 

83 nc += prev[0] 

84 cc += prev[1] 

85 tt += prev[2] 

86 ct += prev[3] 

87 callers[func] = nc, cc, tt, ct 

88 

89 # The following two methods can be called by clients to use 

90 # a profiler to profile a statement, given as a string. 

91 

92 def run(self, cmd): 

93 import __main__ 

94 dict = __main__.__dict__ 

95 return self.runctx(cmd, dict, dict) 

96 

97 def runctx(self, cmd, globals, locals): 

98 self.enable() 

99 try: 

100 exec(cmd, globals, locals) 

101 finally: 

102 self.disable() 

103 return self 

104 

105 # This method is more useful to profile a single function call. 

106 def runcall(self, func, /, *args, **kw): 

107 self.enable() 

108 try: 

109 return func(*args, **kw) 

110 finally: 

111 self.disable() 

112 

113 def __enter__(self): 

114 self.enable() 

115 return self 

116 

117 def __exit__(self, *exc_info): 

118 self.disable() 

119 

120# ____________________________________________________________ 

121 

122def label(code): 

123 if isinstance(code, str): 

124 return ('~', 0, code) # built-in functions ('~' sorts at the end) 

125 else: 

126 return (code.co_filename, code.co_firstlineno, code.co_name) 

127 

128# ____________________________________________________________ 

129 

130def main(): 

131 import os 

132 import sys 

133 import runpy 

134 import pstats 

135 from optparse import OptionParser 

136 usage = "cProfile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..." 

137 parser = OptionParser(usage=usage) 

138 parser.allow_interspersed_args = False 

139 parser.add_option('-o', '--outfile', dest="outfile", 

140 help="Save stats to <outfile>", default=None) 

141 parser.add_option('-s', '--sort', dest="sort", 

142 help="Sort order when printing to stdout, based on pstats.Stats class", 

143 default=-1, 

144 choices=sorted(pstats.Stats.sort_arg_dict_default)) 

145 parser.add_option('-m', dest="module", action="store_true", 

146 help="Profile a library module", default=False) 

147 

148 if not sys.argv[1:]: 

149 parser.print_usage() 

150 sys.exit(2) 

151 

152 (options, args) = parser.parse_args() 

153 sys.argv[:] = args 

154 

155 # The script that we're profiling may chdir, so capture the absolute path 

156 # to the output file at startup. 

157 if options.outfile is not None: 

158 options.outfile = os.path.abspath(options.outfile) 

159 

160 if len(args) > 0: 

161 if options.module: 

162 code = "run_module(modname, run_name='__main__')" 

163 globs = { 

164 'run_module': runpy.run_module, 

165 'modname': args[0] 

166 } 

167 else: 

168 progname = args[0] 

169 sys.path.insert(0, os.path.dirname(progname)) 

170 with open(progname, 'rb') as fp: 

171 code = compile(fp.read(), progname, 'exec') 

172 globs = { 

173 '__file__': progname, 

174 '__name__': '__main__', 

175 '__package__': None, 

176 '__cached__': None, 

177 } 

178 try: 

179 runctx(code, globs, None, options.outfile, options.sort) 

180 except BrokenPipeError as exc: 

181 # Prevent "Exception ignored" during interpreter shutdown. 

182 sys.stdout = None 

183 sys.exit(exc.errno) 

184 else: 

185 parser.print_usage() 

186 return parser 

187 

188# When invoked as main program, invoke the profiler on a script 

189if __name__ == '__main__': 

190 main()