mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	gh-138122: Implement PEP 799 (#138142)
This commit is contained in:
		
							parent
							
								
									f733e428f8
								
							
						
					
					
						commit
						56eb6b64a0
					
				
					 23 changed files with 497 additions and 386 deletions
				
			
		
							
								
								
									
										207
									
								
								Lib/cProfile.py
									
										
									
									
									
								
							
							
						
						
									
										207
									
								
								Lib/cProfile.py
									
										
									
									
									
								
							| 
						 | 
					@ -1,205 +1,14 @@
 | 
				
			||||||
"""Python interface for the 'lsprof' profiler.
 | 
					"""Compatibility wrapper for cProfile module.
 | 
				
			||||||
   Compatible with the 'profile' module.
 | 
					
 | 
				
			||||||
 | 
					This module maintains backward compatibility by importing from the new
 | 
				
			||||||
 | 
					profiling.tracing module.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from profiling.tracing import run, runctx, Profile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__all__ = ["run", "runctx", "Profile"]
 | 
					__all__ = ["run", "runctx", "Profile"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import _lsprof
 | 
					if __name__ == "__main__":
 | 
				
			||||||
import importlib.machinery
 | 
					 | 
				
			||||||
import importlib.util
 | 
					 | 
				
			||||||
import io
 | 
					 | 
				
			||||||
import profile as _pyprofile
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# ____________________________________________________________
 | 
					 | 
				
			||||||
# Simple interface
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def run(statement, filename=None, sort=-1):
 | 
					 | 
				
			||||||
    return _pyprofile._Utils(Profile).run(statement, filename, sort)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def runctx(statement, globals, locals, filename=None, sort=-1):
 | 
					 | 
				
			||||||
    return _pyprofile._Utils(Profile).runctx(statement, globals, locals,
 | 
					 | 
				
			||||||
                                             filename, sort)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
run.__doc__ = _pyprofile.run.__doc__
 | 
					 | 
				
			||||||
runctx.__doc__ = _pyprofile.runctx.__doc__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# ____________________________________________________________
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Profile(_lsprof.Profiler):
 | 
					 | 
				
			||||||
    """Profile(timer=None, timeunit=None, subcalls=True, builtins=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    Builds a profiler object using the specified timer function.
 | 
					 | 
				
			||||||
    The default timer is a fast built-in one based on real time.
 | 
					 | 
				
			||||||
    For custom timer functions returning integers, timeunit can
 | 
					 | 
				
			||||||
    be a float specifying a scale (i.e. how long each integer unit
 | 
					 | 
				
			||||||
    is, in seconds).
 | 
					 | 
				
			||||||
    """
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Most of the functionality is in the base class.
 | 
					 | 
				
			||||||
    # This subclass only adds convenient and backward-compatible methods.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def print_stats(self, sort=-1):
 | 
					 | 
				
			||||||
        import pstats
 | 
					 | 
				
			||||||
        if not isinstance(sort, tuple):
 | 
					 | 
				
			||||||
            sort = (sort,)
 | 
					 | 
				
			||||||
        pstats.Stats(self).strip_dirs().sort_stats(*sort).print_stats()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def dump_stats(self, file):
 | 
					 | 
				
			||||||
        import marshal
 | 
					 | 
				
			||||||
        with open(file, 'wb') as f:
 | 
					 | 
				
			||||||
            self.create_stats()
 | 
					 | 
				
			||||||
            marshal.dump(self.stats, f)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def create_stats(self):
 | 
					 | 
				
			||||||
        self.disable()
 | 
					 | 
				
			||||||
        self.snapshot_stats()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def snapshot_stats(self):
 | 
					 | 
				
			||||||
        entries = self.getstats()
 | 
					 | 
				
			||||||
        self.stats = {}
 | 
					 | 
				
			||||||
        callersdicts = {}
 | 
					 | 
				
			||||||
        # call information
 | 
					 | 
				
			||||||
        for entry in entries:
 | 
					 | 
				
			||||||
            func = label(entry.code)
 | 
					 | 
				
			||||||
            nc = entry.callcount         # ncalls column of pstats (before '/')
 | 
					 | 
				
			||||||
            cc = nc - entry.reccallcount # ncalls column of pstats (after '/')
 | 
					 | 
				
			||||||
            tt = entry.inlinetime        # tottime column of pstats
 | 
					 | 
				
			||||||
            ct = entry.totaltime         # cumtime column of pstats
 | 
					 | 
				
			||||||
            callers = {}
 | 
					 | 
				
			||||||
            callersdicts[id(entry.code)] = callers
 | 
					 | 
				
			||||||
            self.stats[func] = cc, nc, tt, ct, callers
 | 
					 | 
				
			||||||
        # subcall information
 | 
					 | 
				
			||||||
        for entry in entries:
 | 
					 | 
				
			||||||
            if entry.calls:
 | 
					 | 
				
			||||||
                func = label(entry.code)
 | 
					 | 
				
			||||||
                for subentry in entry.calls:
 | 
					 | 
				
			||||||
                    try:
 | 
					 | 
				
			||||||
                        callers = callersdicts[id(subentry.code)]
 | 
					 | 
				
			||||||
                    except KeyError:
 | 
					 | 
				
			||||||
                        continue
 | 
					 | 
				
			||||||
                    nc = subentry.callcount
 | 
					 | 
				
			||||||
                    cc = nc - subentry.reccallcount
 | 
					 | 
				
			||||||
                    tt = subentry.inlinetime
 | 
					 | 
				
			||||||
                    ct = subentry.totaltime
 | 
					 | 
				
			||||||
                    if func in callers:
 | 
					 | 
				
			||||||
                        prev = callers[func]
 | 
					 | 
				
			||||||
                        nc += prev[0]
 | 
					 | 
				
			||||||
                        cc += prev[1]
 | 
					 | 
				
			||||||
                        tt += prev[2]
 | 
					 | 
				
			||||||
                        ct += prev[3]
 | 
					 | 
				
			||||||
                    callers[func] = nc, cc, tt, ct
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # The following two methods can be called by clients to use
 | 
					 | 
				
			||||||
    # a profiler to profile a statement, given as a string.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def run(self, cmd):
 | 
					 | 
				
			||||||
        import __main__
 | 
					 | 
				
			||||||
        dict = __main__.__dict__
 | 
					 | 
				
			||||||
        return self.runctx(cmd, dict, dict)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def runctx(self, cmd, globals, locals):
 | 
					 | 
				
			||||||
        self.enable()
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            exec(cmd, globals, locals)
 | 
					 | 
				
			||||||
        finally:
 | 
					 | 
				
			||||||
            self.disable()
 | 
					 | 
				
			||||||
        return self
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # This method is more useful to profile a single function call.
 | 
					 | 
				
			||||||
    def runcall(self, func, /, *args, **kw):
 | 
					 | 
				
			||||||
        self.enable()
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            return func(*args, **kw)
 | 
					 | 
				
			||||||
        finally:
 | 
					 | 
				
			||||||
            self.disable()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __enter__(self):
 | 
					 | 
				
			||||||
        self.enable()
 | 
					 | 
				
			||||||
        return self
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __exit__(self, *exc_info):
 | 
					 | 
				
			||||||
        self.disable()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# ____________________________________________________________
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def label(code):
 | 
					 | 
				
			||||||
    if isinstance(code, str):
 | 
					 | 
				
			||||||
        return ('~', 0, code)    # built-in functions ('~' sorts at the end)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        return (code.co_filename, code.co_firstlineno, code.co_name)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# ____________________________________________________________
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def main():
 | 
					 | 
				
			||||||
    import os
 | 
					 | 
				
			||||||
    import sys
 | 
					    import sys
 | 
				
			||||||
    import runpy
 | 
					    from profiling.tracing.__main__ import main
 | 
				
			||||||
    import pstats
 | 
					 | 
				
			||||||
    from optparse import OptionParser
 | 
					 | 
				
			||||||
    usage = "cProfile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..."
 | 
					 | 
				
			||||||
    parser = OptionParser(usage=usage)
 | 
					 | 
				
			||||||
    parser.allow_interspersed_args = False
 | 
					 | 
				
			||||||
    parser.add_option('-o', '--outfile', dest="outfile",
 | 
					 | 
				
			||||||
        help="Save stats to <outfile>", default=None)
 | 
					 | 
				
			||||||
    parser.add_option('-s', '--sort', dest="sort",
 | 
					 | 
				
			||||||
        help="Sort order when printing to stdout, based on pstats.Stats class",
 | 
					 | 
				
			||||||
        default=2,
 | 
					 | 
				
			||||||
        choices=sorted(pstats.Stats.sort_arg_dict_default))
 | 
					 | 
				
			||||||
    parser.add_option('-m', dest="module", action="store_true",
 | 
					 | 
				
			||||||
        help="Profile a library module", default=False)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if not sys.argv[1:]:
 | 
					 | 
				
			||||||
        parser.print_usage()
 | 
					 | 
				
			||||||
        sys.exit(2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    (options, args) = parser.parse_args()
 | 
					 | 
				
			||||||
    sys.argv[:] = args
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # The script that we're profiling may chdir, so capture the absolute path
 | 
					 | 
				
			||||||
    # to the output file at startup.
 | 
					 | 
				
			||||||
    if options.outfile is not None:
 | 
					 | 
				
			||||||
        options.outfile = os.path.abspath(options.outfile)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if len(args) > 0:
 | 
					 | 
				
			||||||
        if options.module:
 | 
					 | 
				
			||||||
            code = "run_module(modname, run_name='__main__')"
 | 
					 | 
				
			||||||
            globs = {
 | 
					 | 
				
			||||||
                'run_module': runpy.run_module,
 | 
					 | 
				
			||||||
                'modname': args[0]
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            progname = args[0]
 | 
					 | 
				
			||||||
            sys.path.insert(0, os.path.dirname(progname))
 | 
					 | 
				
			||||||
            with io.open_code(progname) as fp:
 | 
					 | 
				
			||||||
                code = compile(fp.read(), progname, 'exec')
 | 
					 | 
				
			||||||
            spec = importlib.machinery.ModuleSpec(name='__main__', loader=None,
 | 
					 | 
				
			||||||
                                                  origin=progname)
 | 
					 | 
				
			||||||
            module = importlib.util.module_from_spec(spec)
 | 
					 | 
				
			||||||
            # Set __main__ so that importing __main__ in the profiled code will
 | 
					 | 
				
			||||||
            # return the same namespace that the code is executing under.
 | 
					 | 
				
			||||||
            sys.modules['__main__'] = module
 | 
					 | 
				
			||||||
            # Ensure that we're using the same __dict__ instance as the module
 | 
					 | 
				
			||||||
            # for the global variables so that updates to globals are reflected
 | 
					 | 
				
			||||||
            # in the module's namespace.
 | 
					 | 
				
			||||||
            globs = module.__dict__
 | 
					 | 
				
			||||||
            globs.update({
 | 
					 | 
				
			||||||
                '__spec__': spec,
 | 
					 | 
				
			||||||
                '__file__': spec.origin,
 | 
					 | 
				
			||||||
                '__name__': spec.name,
 | 
					 | 
				
			||||||
                '__package__': None,
 | 
					 | 
				
			||||||
                '__cached__': None,
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            runctx(code, globs, None, options.outfile, options.sort)
 | 
					 | 
				
			||||||
        except BrokenPipeError as exc:
 | 
					 | 
				
			||||||
            # Prevent "Exception ignored" during interpreter shutdown.
 | 
					 | 
				
			||||||
            sys.stdout = None
 | 
					 | 
				
			||||||
            sys.exit(exc.errno)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        parser.print_usage()
 | 
					 | 
				
			||||||
    return parser
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# When invoked as main program, invoke the profiler on a script
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					 | 
				
			||||||
    main()
 | 
					    main()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -28,9 +28,18 @@
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
import marshal
 | 
					import marshal
 | 
				
			||||||
 | 
					import warnings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__all__ = ["run", "runctx", "Profile"]
 | 
					__all__ = ["run", "runctx", "Profile"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Emit deprecation warning as per PEP 799
 | 
				
			||||||
 | 
					warnings.warn(
 | 
				
			||||||
 | 
					    "The profile module is deprecated and will be removed in Python 3.17. "
 | 
				
			||||||
 | 
					    "Use profiling.tracing (or cProfile) for tracing profilers instead.",
 | 
				
			||||||
 | 
					    DeprecationWarning,
 | 
				
			||||||
 | 
					    stacklevel=2
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Sample timer for use with
 | 
					# Sample timer for use with
 | 
				
			||||||
#i_count = 0
 | 
					#i_count = 0
 | 
				
			||||||
#def integer_timer():
 | 
					#def integer_timer():
 | 
				
			||||||
| 
						 | 
					@ -550,3 +559,66 @@ def f(m, f1=f1):
 | 
				
			||||||
        return mean
 | 
					        return mean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#****************************************************************************
 | 
					#****************************************************************************
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    import os
 | 
				
			||||||
 | 
					    from optparse import OptionParser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    usage = "profile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..."
 | 
				
			||||||
 | 
					    parser = OptionParser(usage=usage)
 | 
				
			||||||
 | 
					    parser.allow_interspersed_args = False
 | 
				
			||||||
 | 
					    parser.add_option('-o', '--outfile', dest="outfile",
 | 
				
			||||||
 | 
					        help="Save stats to <outfile>", default=None)
 | 
				
			||||||
 | 
					    parser.add_option('-m', dest="module", action="store_true",
 | 
				
			||||||
 | 
					        help="Profile a library module.", default=False)
 | 
				
			||||||
 | 
					    parser.add_option('-s', '--sort', dest="sort",
 | 
				
			||||||
 | 
					        help="Sort order when printing to stdout, based on pstats.Stats class",
 | 
				
			||||||
 | 
					        default=-1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not sys.argv[1:]:
 | 
				
			||||||
 | 
					        parser.print_usage()
 | 
				
			||||||
 | 
					        sys.exit(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (options, args) = parser.parse_args()
 | 
				
			||||||
 | 
					    sys.argv[:] = args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # The script that we're profiling may chdir, so capture the absolute path
 | 
				
			||||||
 | 
					    # to the output file at startup.
 | 
				
			||||||
 | 
					    if options.outfile is not None:
 | 
				
			||||||
 | 
					        options.outfile = os.path.abspath(options.outfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if len(args) > 0:
 | 
				
			||||||
 | 
					        if options.module:
 | 
				
			||||||
 | 
					            import runpy
 | 
				
			||||||
 | 
					            code = "run_module(modname, run_name='__main__')"
 | 
				
			||||||
 | 
					            globs = {
 | 
				
			||||||
 | 
					                'run_module': runpy.run_module,
 | 
				
			||||||
 | 
					                'modname': args[0]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            progname = args[0]
 | 
				
			||||||
 | 
					            sys.path.insert(0, os.path.dirname(progname))
 | 
				
			||||||
 | 
					            with io.open_code(progname) as fp:
 | 
				
			||||||
 | 
					                code = compile(fp.read(), progname, 'exec')
 | 
				
			||||||
 | 
					            spec = importlib.machinery.ModuleSpec(name='__main__', loader=None,
 | 
				
			||||||
 | 
					                                                  origin=progname)
 | 
				
			||||||
 | 
					            globs = {
 | 
				
			||||||
 | 
					                '__spec__': spec,
 | 
				
			||||||
 | 
					                '__file__': spec.origin,
 | 
				
			||||||
 | 
					                '__name__': spec.name,
 | 
				
			||||||
 | 
					                '__package__': None,
 | 
				
			||||||
 | 
					                '__cached__': None,
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            runctx(code, globs, None, options.outfile, options.sort)
 | 
				
			||||||
 | 
					        except BrokenPipeError as exc:
 | 
				
			||||||
 | 
					            # Prevent "Exception ignored" during interpreter shutdown.
 | 
				
			||||||
 | 
					            sys.stdout = None
 | 
				
			||||||
 | 
					            sys.exit(exc.errno)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        parser.print_usage()
 | 
				
			||||||
 | 
					    return parser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# When invoked as main program, invoke the profiler on a script
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
| 
						 | 
					@ -1,6 +0,0 @@
 | 
				
			||||||
from .profile import run
 | 
					 | 
				
			||||||
from .profile import runctx
 | 
					 | 
				
			||||||
from .profile import Profile
 | 
					 | 
				
			||||||
from .profile import _Utils
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
__all__ = ['run', 'runctx', 'Profile']
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,69 +0,0 @@
 | 
				
			||||||
import io
 | 
					 | 
				
			||||||
import importlib.machinery
 | 
					 | 
				
			||||||
import os
 | 
					 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
from optparse import OptionParser
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from .profile import runctx
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def main():
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    usage = "profile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..."
 | 
					 | 
				
			||||||
    parser = OptionParser(usage=usage)
 | 
					 | 
				
			||||||
    parser.allow_interspersed_args = False
 | 
					 | 
				
			||||||
    parser.add_option('-o', '--outfile', dest="outfile",
 | 
					 | 
				
			||||||
        help="Save stats to <outfile>", default=None)
 | 
					 | 
				
			||||||
    parser.add_option('-m', dest="module", action="store_true",
 | 
					 | 
				
			||||||
        help="Profile a library module.", default=False)
 | 
					 | 
				
			||||||
    parser.add_option('-s', '--sort', dest="sort",
 | 
					 | 
				
			||||||
        help="Sort order when printing to stdout, based on pstats.Stats class",
 | 
					 | 
				
			||||||
        default=-1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if not sys.argv[1:]:
 | 
					 | 
				
			||||||
        parser.print_usage()
 | 
					 | 
				
			||||||
        sys.exit(2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    (options, args) = parser.parse_args()
 | 
					 | 
				
			||||||
    sys.argv[:] = args
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # The script that we're profiling may chdir, so capture the absolute path
 | 
					 | 
				
			||||||
    # to the output file at startup.
 | 
					 | 
				
			||||||
    if options.outfile is not None:
 | 
					 | 
				
			||||||
        options.outfile = os.path.abspath(options.outfile)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if len(args) > 0:
 | 
					 | 
				
			||||||
        if options.module:
 | 
					 | 
				
			||||||
            import runpy
 | 
					 | 
				
			||||||
            code = "run_module(modname, run_name='__main__')"
 | 
					 | 
				
			||||||
            globs = {
 | 
					 | 
				
			||||||
                'run_module': runpy.run_module,
 | 
					 | 
				
			||||||
                'modname': args[0]
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            progname = args[0]
 | 
					 | 
				
			||||||
            sys.path.insert(0, os.path.dirname(progname))
 | 
					 | 
				
			||||||
            with io.open_code(progname) as fp:
 | 
					 | 
				
			||||||
                code = compile(fp.read(), progname, 'exec')
 | 
					 | 
				
			||||||
            spec = importlib.machinery.ModuleSpec(name='__main__', loader=None,
 | 
					 | 
				
			||||||
                                                  origin=progname)
 | 
					 | 
				
			||||||
            globs = {
 | 
					 | 
				
			||||||
                '__spec__': spec,
 | 
					 | 
				
			||||||
                '__file__': spec.origin,
 | 
					 | 
				
			||||||
                '__name__': spec.name,
 | 
					 | 
				
			||||||
                '__package__': None,
 | 
					 | 
				
			||||||
                '__cached__': None,
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            runctx(code, globs, None, options.outfile, options.sort)
 | 
					 | 
				
			||||||
        except BrokenPipeError as exc:
 | 
					 | 
				
			||||||
            # Prevent "Exception ignored" during interpreter shutdown.
 | 
					 | 
				
			||||||
            sys.stdout = None
 | 
					 | 
				
			||||||
            sys.exit(exc.errno)
 | 
					 | 
				
			||||||
    else:
 | 
					 | 
				
			||||||
        parser.print_usage()
 | 
					 | 
				
			||||||
    return parser
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# When invoked as main program, invoke the profiler on a script
 | 
					 | 
				
			||||||
if __name__ == '__main__':
 | 
					 | 
				
			||||||
    main()
 | 
					 | 
				
			||||||
							
								
								
									
										13
									
								
								Lib/profiling/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								Lib/profiling/__init__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,13 @@
 | 
				
			||||||
 | 
					"""Python profiling tools.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This package provides two types of profilers:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- profiling.tracing: Deterministic tracing profiler that instruments every
 | 
				
			||||||
 | 
					  function call and return. Higher overhead but provides exact call counts
 | 
				
			||||||
 | 
					  and timing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- profiling.sampling: Statistical sampling profiler that periodically samples
 | 
				
			||||||
 | 
					  the call stack. Low overhead and suitable for production use.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__all__ = ("tracing", "sampling")
 | 
				
			||||||
							
								
								
									
										11
									
								
								Lib/profiling/sampling/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Lib/profiling/sampling/__init__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					"""Statistical sampling profiler for Python.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This module provides low-overhead profiling by periodically sampling the
 | 
				
			||||||
 | 
					call stack rather than tracing every function call.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .collector import Collector
 | 
				
			||||||
 | 
					from .pstats_collector import PstatsCollector
 | 
				
			||||||
 | 
					from .stack_collector import CollapsedStackCollector
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__all__ = ("Collector", "PstatsCollector", "CollapsedStackCollector")
 | 
				
			||||||
							
								
								
									
										6
									
								
								Lib/profiling/sampling/__main__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Lib/profiling/sampling/__main__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					"""Run the sampling profiler from the command line."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from .sample import main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
| 
						 | 
					@ -25,40 +25,40 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Examples:
 | 
					Examples:
 | 
				
			||||||
  # Profile process 1234 for 10 seconds with default settings
 | 
					  # Profile process 1234 for 10 seconds with default settings
 | 
				
			||||||
  python -m profile.sample -p 1234
 | 
					  python -m profiling.sampling -p 1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Profile a script by running it in a subprocess
 | 
					  # Profile a script by running it in a subprocess
 | 
				
			||||||
  python -m profile.sample myscript.py arg1 arg2
 | 
					  python -m profiling.sampling myscript.py arg1 arg2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Profile a module by running it as python -m module in a subprocess
 | 
					  # Profile a module by running it as python -m module in a subprocess
 | 
				
			||||||
  python -m profile.sample -m mymodule arg1 arg2
 | 
					  python -m profiling.sampling -m mymodule arg1 arg2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Profile with custom interval and duration, save to file
 | 
					  # Profile with custom interval and duration, save to file
 | 
				
			||||||
  python -m profile.sample -i 50 -d 30 -o profile.stats -p 1234
 | 
					  python -m profiling.sampling -i 50 -d 30 -o profile.stats -p 1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Generate collapsed stacks for flamegraph
 | 
					  # Generate collapsed stacks for flamegraph
 | 
				
			||||||
  python -m profile.sample --collapsed -p 1234
 | 
					  python -m profiling.sampling --collapsed -p 1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Profile all threads, sort by total time
 | 
					  # Profile all threads, sort by total time
 | 
				
			||||||
  python -m profile.sample -a --sort-tottime -p 1234
 | 
					  python -m profiling.sampling -a --sort-tottime -p 1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Profile for 1 minute with 1ms sampling interval
 | 
					  # Profile for 1 minute with 1ms sampling interval
 | 
				
			||||||
  python -m profile.sample -i 1000 -d 60 -p 1234
 | 
					  python -m profiling.sampling -i 1000 -d 60 -p 1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Show only top 20 functions sorted by direct samples
 | 
					  # Show only top 20 functions sorted by direct samples
 | 
				
			||||||
  python -m profile.sample --sort-nsamples -l 20 -p 1234
 | 
					  python -m profiling.sampling --sort-nsamples -l 20 -p 1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Profile all threads and save collapsed stacks
 | 
					  # Profile all threads and save collapsed stacks
 | 
				
			||||||
  python -m profile.sample -a --collapsed -o stacks.txt -p 1234
 | 
					  python -m profiling.sampling -a --collapsed -o stacks.txt -p 1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Profile with real-time sampling statistics
 | 
					  # Profile with real-time sampling statistics
 | 
				
			||||||
  python -m profile.sample --realtime-stats -p 1234
 | 
					  python -m profiling.sampling --realtime-stats -p 1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Sort by sample percentage to find most sampled functions
 | 
					  # Sort by sample percentage to find most sampled functions
 | 
				
			||||||
  python -m profile.sample --sort-sample-pct -p 1234
 | 
					  python -m profiling.sampling --sort-sample-pct -p 1234
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Sort by cumulative samples to find functions most on call stack
 | 
					  # Sort by cumulative samples to find functions most on call stack
 | 
				
			||||||
  python -m profile.sample --sort-nsamples-cumul -p 1234"""
 | 
					  python -m profiling.sampling --sort-nsamples-cumul -p 1234"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Constants for socket synchronization
 | 
					# Constants for socket synchronization
 | 
				
			||||||
| 
						 | 
					@ -84,7 +84,7 @@ def _run_with_sync(original_cmd):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Build command using the sync coordinator
 | 
					        # Build command using the sync coordinator
 | 
				
			||||||
        target_args = original_cmd[1:]  # Remove python executable
 | 
					        target_args = original_cmd[1:]  # Remove python executable
 | 
				
			||||||
        cmd = (sys.executable, "-m", "profile._sync_coordinator", str(sync_port), cwd) + tuple(target_args)
 | 
					        cmd = (sys.executable, "-m", "profiling.sampling._sync_coordinator", str(sync_port), cwd) + tuple(target_args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Start the process with coordinator
 | 
					        # Start the process with coordinator
 | 
				
			||||||
        process = subprocess.Popen(cmd)
 | 
					        process = subprocess.Popen(cmd)
 | 
				
			||||||
							
								
								
									
										219
									
								
								Lib/profiling/tracing/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								Lib/profiling/tracing/__init__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,219 @@
 | 
				
			||||||
 | 
					"""Tracing profiler for Python.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This module provides deterministic profiling of Python programs by tracing
 | 
				
			||||||
 | 
					every function call and return.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__all__ = ("run", "runctx", "Profile")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import _lsprof
 | 
				
			||||||
 | 
					import importlib.machinery
 | 
				
			||||||
 | 
					import importlib.util
 | 
				
			||||||
 | 
					import io
 | 
				
			||||||
 | 
					from profiling.tracing._utils import _Utils
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ____________________________________________________________
 | 
				
			||||||
 | 
					# Simple interface
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def run(statement, filename=None, sort=-1):
 | 
				
			||||||
 | 
					    """Run statement under profiler optionally saving results in filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This function takes a single argument that can be passed to the
 | 
				
			||||||
 | 
					    "exec" statement, and an optional file name.  In all cases this
 | 
				
			||||||
 | 
					    routine attempts to "exec" its first argument and gather profiling
 | 
				
			||||||
 | 
					    statistics from the execution. If no file name is present, then this
 | 
				
			||||||
 | 
					    function automatically prints a simple profiling report, sorted by the
 | 
				
			||||||
 | 
					    standard name string (file/line/function-name) that is presented in
 | 
				
			||||||
 | 
					    each line.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    return _Utils(Profile).run(statement, filename, sort)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def runctx(statement, globals, locals, filename=None, sort=-1):
 | 
				
			||||||
 | 
					    """Run statement under profiler, supplying your own globals and locals,
 | 
				
			||||||
 | 
					    optionally saving results in filename.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    statement and filename have the same semantics as profile.run
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    return _Utils(Profile).runctx(statement, globals, locals,
 | 
				
			||||||
 | 
					                                             filename, sort)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ____________________________________________________________
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Profile(_lsprof.Profiler):
 | 
				
			||||||
 | 
					    """Profile(timer=None, timeunit=None, subcalls=True, builtins=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Builds a profiler object using the specified timer function.
 | 
				
			||||||
 | 
					    The default timer is a fast built-in one based on real time.
 | 
				
			||||||
 | 
					    For custom timer functions returning integers, timeunit can
 | 
				
			||||||
 | 
					    be a float specifying a scale (i.e. how long each integer unit
 | 
				
			||||||
 | 
					    is, in seconds).
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Most of the functionality is in the base class.
 | 
				
			||||||
 | 
					    # This subclass only adds convenient and backward-compatible methods.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def print_stats(self, sort=-1):
 | 
				
			||||||
 | 
					        import pstats
 | 
				
			||||||
 | 
					        if not isinstance(sort, tuple):
 | 
				
			||||||
 | 
					            sort = (sort,)
 | 
				
			||||||
 | 
					        pstats.Stats(self).strip_dirs().sort_stats(*sort).print_stats()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dump_stats(self, file):
 | 
				
			||||||
 | 
					        import marshal
 | 
				
			||||||
 | 
					        with open(file, 'wb') as f:
 | 
				
			||||||
 | 
					            self.create_stats()
 | 
				
			||||||
 | 
					            marshal.dump(self.stats, f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_stats(self):
 | 
				
			||||||
 | 
					        self.disable()
 | 
				
			||||||
 | 
					        self.snapshot_stats()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def snapshot_stats(self):
 | 
				
			||||||
 | 
					        entries = self.getstats()
 | 
				
			||||||
 | 
					        self.stats = {}
 | 
				
			||||||
 | 
					        callersdicts = {}
 | 
				
			||||||
 | 
					        # call information
 | 
				
			||||||
 | 
					        for entry in entries:
 | 
				
			||||||
 | 
					            func = label(entry.code)
 | 
				
			||||||
 | 
					            nc = entry.callcount         # ncalls column of pstats (before '/')
 | 
				
			||||||
 | 
					            cc = nc - entry.reccallcount # ncalls column of pstats (after '/')
 | 
				
			||||||
 | 
					            tt = entry.inlinetime        # tottime column of pstats
 | 
				
			||||||
 | 
					            ct = entry.totaltime         # cumtime column of pstats
 | 
				
			||||||
 | 
					            callers = {}
 | 
				
			||||||
 | 
					            callersdicts[id(entry.code)] = callers
 | 
				
			||||||
 | 
					            self.stats[func] = cc, nc, tt, ct, callers
 | 
				
			||||||
 | 
					        # subcall information
 | 
				
			||||||
 | 
					        for entry in entries:
 | 
				
			||||||
 | 
					            if entry.calls:
 | 
				
			||||||
 | 
					                func = label(entry.code)
 | 
				
			||||||
 | 
					                for subentry in entry.calls:
 | 
				
			||||||
 | 
					                    try:
 | 
				
			||||||
 | 
					                        callers = callersdicts[id(subentry.code)]
 | 
				
			||||||
 | 
					                    except KeyError:
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					                    nc = subentry.callcount
 | 
				
			||||||
 | 
					                    cc = nc - subentry.reccallcount
 | 
				
			||||||
 | 
					                    tt = subentry.inlinetime
 | 
				
			||||||
 | 
					                    ct = subentry.totaltime
 | 
				
			||||||
 | 
					                    if func in callers:
 | 
				
			||||||
 | 
					                        prev = callers[func]
 | 
				
			||||||
 | 
					                        nc += prev[0]
 | 
				
			||||||
 | 
					                        cc += prev[1]
 | 
				
			||||||
 | 
					                        tt += prev[2]
 | 
				
			||||||
 | 
					                        ct += prev[3]
 | 
				
			||||||
 | 
					                    callers[func] = nc, cc, tt, ct
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # The following two methods can be called by clients to use
 | 
				
			||||||
 | 
					    # a profiler to profile a statement, given as a string.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self, cmd):
 | 
				
			||||||
 | 
					        import __main__
 | 
				
			||||||
 | 
					        dict = __main__.__dict__
 | 
				
			||||||
 | 
					        return self.runctx(cmd, dict, dict)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def runctx(self, cmd, globals, locals):
 | 
				
			||||||
 | 
					        self.enable()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            exec(cmd, globals, locals)
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self.disable()
 | 
				
			||||||
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # This method is more useful to profile a single function call.
 | 
				
			||||||
 | 
					    def runcall(self, func, /, *args, **kw):
 | 
				
			||||||
 | 
					        self.enable()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return func(*args, **kw)
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self.disable()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __enter__(self):
 | 
				
			||||||
 | 
					        self.enable()
 | 
				
			||||||
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __exit__(self, *exc_info):
 | 
				
			||||||
 | 
					        self.disable()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ____________________________________________________________
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def label(code):
 | 
				
			||||||
 | 
					    if isinstance(code, str):
 | 
				
			||||||
 | 
					        return ('~', 0, code)    # built-in functions ('~' sorts at the end)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        return (code.co_filename, code.co_firstlineno, code.co_name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ____________________________________________________________
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    import os
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    import runpy
 | 
				
			||||||
 | 
					    import pstats
 | 
				
			||||||
 | 
					    from optparse import OptionParser
 | 
				
			||||||
 | 
					    usage = "cProfile.py [-o output_file_path] [-s sort] [-m module | scriptfile] [arg] ..."
 | 
				
			||||||
 | 
					    parser = OptionParser(usage=usage)
 | 
				
			||||||
 | 
					    parser.allow_interspersed_args = False
 | 
				
			||||||
 | 
					    parser.add_option('-o', '--outfile', dest="outfile",
 | 
				
			||||||
 | 
					        help="Save stats to <outfile>", default=None)
 | 
				
			||||||
 | 
					    parser.add_option('-s', '--sort', dest="sort",
 | 
				
			||||||
 | 
					        help="Sort order when printing to stdout, based on pstats.Stats class",
 | 
				
			||||||
 | 
					        default=2,
 | 
				
			||||||
 | 
					        choices=sorted(pstats.Stats.sort_arg_dict_default))
 | 
				
			||||||
 | 
					    parser.add_option('-m', dest="module", action="store_true",
 | 
				
			||||||
 | 
					        help="Profile a library module", default=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not sys.argv[1:]:
 | 
				
			||||||
 | 
					        parser.print_usage()
 | 
				
			||||||
 | 
					        sys.exit(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    (options, args) = parser.parse_args()
 | 
				
			||||||
 | 
					    sys.argv[:] = args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # The script that we're profiling may chdir, so capture the absolute path
 | 
				
			||||||
 | 
					    # to the output file at startup.
 | 
				
			||||||
 | 
					    if options.outfile is not None:
 | 
				
			||||||
 | 
					        options.outfile = os.path.abspath(options.outfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if len(args) > 0:
 | 
				
			||||||
 | 
					        if options.module:
 | 
				
			||||||
 | 
					            code = "run_module(modname, run_name='__main__')"
 | 
				
			||||||
 | 
					            globs = {
 | 
				
			||||||
 | 
					                'run_module': runpy.run_module,
 | 
				
			||||||
 | 
					                'modname': args[0]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            progname = args[0]
 | 
				
			||||||
 | 
					            sys.path.insert(0, os.path.dirname(progname))
 | 
				
			||||||
 | 
					            with io.open_code(progname) as fp:
 | 
				
			||||||
 | 
					                code = compile(fp.read(), progname, 'exec')
 | 
				
			||||||
 | 
					            spec = importlib.machinery.ModuleSpec(name='__main__', loader=None,
 | 
				
			||||||
 | 
					                                                  origin=progname)
 | 
				
			||||||
 | 
					            module = importlib.util.module_from_spec(spec)
 | 
				
			||||||
 | 
					            # Set __main__ so that importing __main__ in the profiled code will
 | 
				
			||||||
 | 
					            # return the same namespace that the code is executing under.
 | 
				
			||||||
 | 
					            sys.modules['__main__'] = module
 | 
				
			||||||
 | 
					            # Ensure that we're using the same __dict__ instance as the module
 | 
				
			||||||
 | 
					            # for the global variables so that updates to globals are reflected
 | 
				
			||||||
 | 
					            # in the module's namespace.
 | 
				
			||||||
 | 
					            globs = module.__dict__
 | 
				
			||||||
 | 
					            globs.update({
 | 
				
			||||||
 | 
					                '__spec__': spec,
 | 
				
			||||||
 | 
					                '__file__': spec.origin,
 | 
				
			||||||
 | 
					                '__name__': spec.name,
 | 
				
			||||||
 | 
					                '__package__': None,
 | 
				
			||||||
 | 
					                '__cached__': None,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            runctx(code, globs, None, options.outfile, options.sort)
 | 
				
			||||||
 | 
					        except BrokenPipeError as exc:
 | 
				
			||||||
 | 
					            # Prevent "Exception ignored" during interpreter shutdown.
 | 
				
			||||||
 | 
					            sys.stdout = None
 | 
				
			||||||
 | 
					            sys.exit(exc.errno)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        parser.print_usage()
 | 
				
			||||||
 | 
					    return parser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# When invoked as main program, invoke the profiler on a script
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										6
									
								
								Lib/profiling/tracing/__main__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								Lib/profiling/tracing/__main__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,6 @@
 | 
				
			||||||
 | 
					"""Run the tracing profiler from the command line."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from profiling.tracing import main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										32
									
								
								Lib/profiling/tracing/_utils.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								Lib/profiling/tracing/_utils.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					class _Utils:
 | 
				
			||||||
 | 
					    """Support class for utility functions which are shared by
 | 
				
			||||||
 | 
					    profile.py and cProfile.py modules.
 | 
				
			||||||
 | 
					    Not supposed to be used directly.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, profiler):
 | 
				
			||||||
 | 
					        self.profiler = profiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self, statement, filename, sort):
 | 
				
			||||||
 | 
					        prof = self.profiler()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            prof.run(statement)
 | 
				
			||||||
 | 
					        except SystemExit:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self._show(prof, filename, sort)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def runctx(self, statement, globals, locals, filename, sort):
 | 
				
			||||||
 | 
					        prof = self.profiler()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            prof.runctx(statement, globals, locals)
 | 
				
			||||||
 | 
					        except SystemExit:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self._show(prof, filename, sort)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _show(self, prof, filename, sort):
 | 
				
			||||||
 | 
					        if filename is not None:
 | 
				
			||||||
 | 
					            prof.dump_stats(filename)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            prof.print_stats(sort)
 | 
				
			||||||
| 
						 | 
					@ -4,11 +4,15 @@
 | 
				
			||||||
import pstats
 | 
					import pstats
 | 
				
			||||||
import unittest
 | 
					import unittest
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					import warnings
 | 
				
			||||||
from difflib import unified_diff
 | 
					from difflib import unified_diff
 | 
				
			||||||
from io import StringIO
 | 
					from io import StringIO
 | 
				
			||||||
from test.support.os_helper import TESTFN, unlink, temp_dir, change_cwd
 | 
					from test.support.os_helper import TESTFN, unlink, temp_dir, change_cwd
 | 
				
			||||||
from contextlib import contextmanager, redirect_stdout
 | 
					from contextlib import contextmanager, redirect_stdout
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Suppress deprecation warning for profile module (PEP 799)
 | 
				
			||||||
 | 
					with warnings.catch_warnings():
 | 
				
			||||||
 | 
					    warnings.simplefilter("ignore", DeprecationWarning)
 | 
				
			||||||
    import profile
 | 
					    import profile
 | 
				
			||||||
from test.profilee import testfunc, timer
 | 
					from test.profilee import testfunc, timer
 | 
				
			||||||
from test.support.script_helper import assert_python_failure, assert_python_ok
 | 
					from test.support.script_helper import assert_python_failure, assert_python_ok
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								Lib/test/test_profiling/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								Lib/test/test_profiling/__init__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					from test.support import load_package_tests
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def load_tests(*args):
 | 
				
			||||||
 | 
					    return load_package_tests(os.path.dirname(__file__), *args)
 | 
				
			||||||
							
								
								
									
										4
									
								
								Lib/test/test_profiling/__main__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								Lib/test/test_profiling/__main__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					from . import load_tests
 | 
				
			||||||
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unittest.main()
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
"""Tests for the sampling profiler (profile.sample)."""
 | 
					"""Tests for the sampling profiler (profiling.sampling)."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import contextlib
 | 
					import contextlib
 | 
				
			||||||
import io
 | 
					import io
 | 
				
			||||||
| 
						 | 
					@ -12,8 +12,8 @@
 | 
				
			||||||
import unittest
 | 
					import unittest
 | 
				
			||||||
from unittest import mock
 | 
					from unittest import mock
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from profile.pstats_collector import PstatsCollector
 | 
					from profiling.sampling.pstats_collector import PstatsCollector
 | 
				
			||||||
from profile.stack_collector import (
 | 
					from profiling.sampling.stack_collector import (
 | 
				
			||||||
    CollapsedStackCollector,
 | 
					    CollapsedStackCollector,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,8 +32,8 @@
 | 
				
			||||||
        "Test only runs when _remote_debugging is available"
 | 
					        "Test only runs when _remote_debugging is available"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
else:
 | 
					else:
 | 
				
			||||||
    import profile.sample
 | 
					    import profiling.sampling
 | 
				
			||||||
    from profile.sample import SampleProfiler
 | 
					    from profiling.sampling.sample import SampleProfiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -472,7 +472,7 @@ class TestSampleProfiler(unittest.TestCase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_sample_profiler_initialization(self):
 | 
					    def test_sample_profiler_initialization(self):
 | 
				
			||||||
        """Test SampleProfiler initialization with various parameters."""
 | 
					        """Test SampleProfiler initialization with various parameters."""
 | 
				
			||||||
        from profile.sample import SampleProfiler
 | 
					        from profiling.sampling.sample import SampleProfiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Mock RemoteUnwinder to avoid permission issues
 | 
					        # Mock RemoteUnwinder to avoid permission issues
 | 
				
			||||||
        with mock.patch(
 | 
					        with mock.patch(
 | 
				
			||||||
| 
						 | 
					@ -498,7 +498,7 @@ def test_sample_profiler_initialization(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_sample_profiler_sample_method_timing(self):
 | 
					    def test_sample_profiler_sample_method_timing(self):
 | 
				
			||||||
        """Test that the sample method respects duration and handles timing correctly."""
 | 
					        """Test that the sample method respects duration and handles timing correctly."""
 | 
				
			||||||
        from profile.sample import SampleProfiler
 | 
					        from profiling.sampling.sample import SampleProfiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Mock the unwinder to avoid needing a real process
 | 
					        # Mock the unwinder to avoid needing a real process
 | 
				
			||||||
        mock_unwinder = mock.MagicMock()
 | 
					        mock_unwinder = mock.MagicMock()
 | 
				
			||||||
| 
						 | 
					@ -548,7 +548,7 @@ def test_sample_profiler_sample_method_timing(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_sample_profiler_error_handling(self):
 | 
					    def test_sample_profiler_error_handling(self):
 | 
				
			||||||
        """Test that the sample method handles errors gracefully."""
 | 
					        """Test that the sample method handles errors gracefully."""
 | 
				
			||||||
        from profile.sample import SampleProfiler
 | 
					        from profiling.sampling.sample import SampleProfiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Mock unwinder that raises errors
 | 
					        # Mock unwinder that raises errors
 | 
				
			||||||
        mock_unwinder = mock.MagicMock()
 | 
					        mock_unwinder = mock.MagicMock()
 | 
				
			||||||
| 
						 | 
					@ -612,7 +612,7 @@ def test_sample_profiler_error_handling(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_sample_profiler_missed_samples_warning(self):
 | 
					    def test_sample_profiler_missed_samples_warning(self):
 | 
				
			||||||
        """Test that the profiler warns about missed samples when sampling is too slow."""
 | 
					        """Test that the profiler warns about missed samples when sampling is too slow."""
 | 
				
			||||||
        from profile.sample import SampleProfiler
 | 
					        from profiling.sampling.sample import SampleProfiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mock_unwinder = mock.MagicMock()
 | 
					        mock_unwinder = mock.MagicMock()
 | 
				
			||||||
        mock_unwinder.get_stack_trace.return_value = [
 | 
					        mock_unwinder.get_stack_trace.return_value = [
 | 
				
			||||||
| 
						 | 
					@ -698,7 +698,7 @@ def setUp(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_basic(self):
 | 
					    def test_print_sampled_stats_basic(self):
 | 
				
			||||||
        """Test basic print_sampled_stats functionality."""
 | 
					        """Test basic print_sampled_stats functionality."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Capture output
 | 
					        # Capture output
 | 
				
			||||||
        with io.StringIO() as output:
 | 
					        with io.StringIO() as output:
 | 
				
			||||||
| 
						 | 
					@ -720,7 +720,7 @@ def test_print_sampled_stats_basic(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_sorting(self):
 | 
					    def test_print_sampled_stats_sorting(self):
 | 
				
			||||||
        """Test different sorting options."""
 | 
					        """Test different sorting options."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test sort by calls
 | 
					        # Test sort by calls
 | 
				
			||||||
        with io.StringIO() as output:
 | 
					        with io.StringIO() as output:
 | 
				
			||||||
| 
						 | 
					@ -753,7 +753,7 @@ def test_print_sampled_stats_sorting(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_limit(self):
 | 
					    def test_print_sampled_stats_limit(self):
 | 
				
			||||||
        """Test limiting output rows."""
 | 
					        """Test limiting output rows."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with io.StringIO() as output:
 | 
					        with io.StringIO() as output:
 | 
				
			||||||
            with mock.patch("sys.stdout", output):
 | 
					            with mock.patch("sys.stdout", output):
 | 
				
			||||||
| 
						 | 
					@ -782,7 +782,7 @@ def test_print_sampled_stats_limit(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_time_units(self):
 | 
					    def test_print_sampled_stats_time_units(self):
 | 
				
			||||||
        """Test proper time unit selection."""
 | 
					        """Test proper time unit selection."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with io.StringIO() as output:
 | 
					        with io.StringIO() as output:
 | 
				
			||||||
            with mock.patch("sys.stdout", output):
 | 
					            with mock.patch("sys.stdout", output):
 | 
				
			||||||
| 
						 | 
					@ -812,7 +812,7 @@ def test_print_sampled_stats_time_units(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_summary(self):
 | 
					    def test_print_sampled_stats_summary(self):
 | 
				
			||||||
        """Test summary section generation."""
 | 
					        """Test summary section generation."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with io.StringIO() as output:
 | 
					        with io.StringIO() as output:
 | 
				
			||||||
            with mock.patch("sys.stdout", output):
 | 
					            with mock.patch("sys.stdout", output):
 | 
				
			||||||
| 
						 | 
					@ -840,7 +840,7 @@ def test_print_sampled_stats_summary(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_no_summary(self):
 | 
					    def test_print_sampled_stats_no_summary(self):
 | 
				
			||||||
        """Test disabling summary output."""
 | 
					        """Test disabling summary output."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with io.StringIO() as output:
 | 
					        with io.StringIO() as output:
 | 
				
			||||||
            with mock.patch("sys.stdout", output):
 | 
					            with mock.patch("sys.stdout", output):
 | 
				
			||||||
| 
						 | 
					@ -857,7 +857,7 @@ def test_print_sampled_stats_no_summary(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_empty_stats(self):
 | 
					    def test_print_sampled_stats_empty_stats(self):
 | 
				
			||||||
        """Test with empty stats."""
 | 
					        """Test with empty stats."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        empty_stats = mock.MagicMock()
 | 
					        empty_stats = mock.MagicMock()
 | 
				
			||||||
        empty_stats.stats = {}
 | 
					        empty_stats.stats = {}
 | 
				
			||||||
| 
						 | 
					@ -873,7 +873,7 @@ def test_print_sampled_stats_empty_stats(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_sample_percentage_sorting(self):
 | 
					    def test_print_sampled_stats_sample_percentage_sorting(self):
 | 
				
			||||||
        """Test sample percentage sorting options."""
 | 
					        """Test sample percentage sorting options."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Add a function with high sample percentage (more direct calls than func3's 200)
 | 
					        # Add a function with high sample percentage (more direct calls than func3's 200)
 | 
				
			||||||
        self.mock_stats.stats[("expensive.py", 60, "expensive_func")] = (
 | 
					        self.mock_stats.stats[("expensive.py", 60, "expensive_func")] = (
 | 
				
			||||||
| 
						 | 
					@ -900,7 +900,7 @@ def test_print_sampled_stats_sample_percentage_sorting(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_with_recursive_calls(self):
 | 
					    def test_print_sampled_stats_with_recursive_calls(self):
 | 
				
			||||||
        """Test print_sampled_stats with recursive calls where nc != cc."""
 | 
					        """Test print_sampled_stats with recursive calls where nc != cc."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Create stats with recursive calls (nc != cc)
 | 
					        # Create stats with recursive calls (nc != cc)
 | 
				
			||||||
        recursive_stats = mock.MagicMock()
 | 
					        recursive_stats = mock.MagicMock()
 | 
				
			||||||
| 
						 | 
					@ -936,7 +936,7 @@ def test_print_sampled_stats_with_recursive_calls(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_with_zero_call_counts(self):
 | 
					    def test_print_sampled_stats_with_zero_call_counts(self):
 | 
				
			||||||
        """Test print_sampled_stats with zero call counts to trigger division protection."""
 | 
					        """Test print_sampled_stats with zero call counts to trigger division protection."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Create stats with zero call counts
 | 
					        # Create stats with zero call counts
 | 
				
			||||||
        zero_stats = mock.MagicMock()
 | 
					        zero_stats = mock.MagicMock()
 | 
				
			||||||
| 
						 | 
					@ -964,7 +964,7 @@ def test_print_sampled_stats_with_zero_call_counts(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_sort_by_name(self):
 | 
					    def test_print_sampled_stats_sort_by_name(self):
 | 
				
			||||||
        """Test sort by function name option."""
 | 
					        """Test sort by function name option."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with io.StringIO() as output:
 | 
					        with io.StringIO() as output:
 | 
				
			||||||
            with mock.patch("sys.stdout", output):
 | 
					            with mock.patch("sys.stdout", output):
 | 
				
			||||||
| 
						 | 
					@ -1022,7 +1022,7 @@ def test_print_sampled_stats_sort_by_name(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_with_zero_time_functions(self):
 | 
					    def test_print_sampled_stats_with_zero_time_functions(self):
 | 
				
			||||||
        """Test summary sections with functions that have zero time."""
 | 
					        """Test summary sections with functions that have zero time."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Create stats with zero-time functions
 | 
					        # Create stats with zero-time functions
 | 
				
			||||||
        zero_time_stats = mock.MagicMock()
 | 
					        zero_time_stats = mock.MagicMock()
 | 
				
			||||||
| 
						 | 
					@ -1060,7 +1060,7 @@ def test_print_sampled_stats_with_zero_time_functions(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_print_sampled_stats_with_malformed_qualified_names(self):
 | 
					    def test_print_sampled_stats_with_malformed_qualified_names(self):
 | 
				
			||||||
        """Test summary generation with function names that don't contain colons."""
 | 
					        """Test summary generation with function names that don't contain colons."""
 | 
				
			||||||
        from profile.sample import print_sampled_stats
 | 
					        from profiling.sampling.sample import print_sampled_stats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Create stats with function names that would create malformed qualified names
 | 
					        # Create stats with function names that would create malformed qualified names
 | 
				
			||||||
        malformed_stats = mock.MagicMock()
 | 
					        malformed_stats = mock.MagicMock()
 | 
				
			||||||
| 
						 | 
					@ -1451,7 +1451,7 @@ def test_sampling_basic_functionality(self):
 | 
				
			||||||
            mock.patch("sys.stdout", captured_output),
 | 
					            mock.patch("sys.stdout", captured_output),
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                profile.sample.sample(
 | 
					                profiling.sampling.sample.sample(
 | 
				
			||||||
                    proc.pid,
 | 
					                    proc.pid,
 | 
				
			||||||
                    duration_sec=2,
 | 
					                    duration_sec=2,
 | 
				
			||||||
                    sample_interval_usec=1000,  # 1ms
 | 
					                    sample_interval_usec=1000,  # 1ms
 | 
				
			||||||
| 
						 | 
					@ -1483,7 +1483,7 @@ def test_sampling_with_pstats_export(self):
 | 
				
			||||||
                mock.patch("sys.stdout", captured_output),
 | 
					                mock.patch("sys.stdout", captured_output),
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    profile.sample.sample(
 | 
					                    profiling.sampling.sample.sample(
 | 
				
			||||||
                        proc.pid,
 | 
					                        proc.pid,
 | 
				
			||||||
                        duration_sec=1,
 | 
					                        duration_sec=1,
 | 
				
			||||||
                        filename=pstats_out.name,
 | 
					                        filename=pstats_out.name,
 | 
				
			||||||
| 
						 | 
					@ -1528,7 +1528,7 @@ def test_sampling_with_collapsed_export(self):
 | 
				
			||||||
                mock.patch("sys.stdout", captured_output),
 | 
					                mock.patch("sys.stdout", captured_output),
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    profile.sample.sample(
 | 
					                    profiling.sampling.sample.sample(
 | 
				
			||||||
                        proc.pid,
 | 
					                        proc.pid,
 | 
				
			||||||
                        duration_sec=1,
 | 
					                        duration_sec=1,
 | 
				
			||||||
                        filename=collapsed_file.name,
 | 
					                        filename=collapsed_file.name,
 | 
				
			||||||
| 
						 | 
					@ -1576,7 +1576,7 @@ def test_sampling_all_threads(self):
 | 
				
			||||||
            mock.patch("sys.stdout", captured_output),
 | 
					            mock.patch("sys.stdout", captured_output),
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                profile.sample.sample(
 | 
					                profiling.sampling.sample.sample(
 | 
				
			||||||
                    proc.pid,
 | 
					                    proc.pid,
 | 
				
			||||||
                    duration_sec=1,
 | 
					                    duration_sec=1,
 | 
				
			||||||
                    all_threads=True,
 | 
					                    all_threads=True,
 | 
				
			||||||
| 
						 | 
					@ -1595,7 +1595,7 @@ def test_sample_target_script(self):
 | 
				
			||||||
        script_file.flush()
 | 
					        script_file.flush()
 | 
				
			||||||
        self.addCleanup(close_and_unlink, script_file)
 | 
					        self.addCleanup(close_and_unlink, script_file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        test_args = ["profile.sample", "-d", "1", script_file.name]
 | 
					        test_args = ["profiling.sampling.sample", "-d", "1", script_file.name]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
| 
						 | 
					@ -1603,7 +1603,7 @@ def test_sample_target_script(self):
 | 
				
			||||||
            mock.patch("sys.stdout", captured_output),
 | 
					            mock.patch("sys.stdout", captured_output),
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                profile.sample.main()
 | 
					                profiling.sampling.sample.main()
 | 
				
			||||||
            except PermissionError:
 | 
					            except PermissionError:
 | 
				
			||||||
                self.skipTest("Insufficient permissions for remote profiling")
 | 
					                self.skipTest("Insufficient permissions for remote profiling")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1627,7 +1627,7 @@ def test_sample_target_module(self):
 | 
				
			||||||
        with open(module_path, "w") as f:
 | 
					        with open(module_path, "w") as f:
 | 
				
			||||||
            f.write(self.test_script)
 | 
					            f.write(self.test_script)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        test_args = ["profile.sample", "-d", "1", "-m", "test_module"]
 | 
					        test_args = ["profiling.sampling.sample", "-d", "1", "-m", "test_module"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
| 
						 | 
					@ -1637,7 +1637,7 @@ def test_sample_target_module(self):
 | 
				
			||||||
            contextlib.chdir(tempdir.name),
 | 
					            contextlib.chdir(tempdir.name),
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            try:
 | 
					            try:
 | 
				
			||||||
                profile.sample.main()
 | 
					                profiling.sampling.sample.main()
 | 
				
			||||||
            except PermissionError:
 | 
					            except PermissionError:
 | 
				
			||||||
                self.skipTest("Insufficient permissions for remote profiling")
 | 
					                self.skipTest("Insufficient permissions for remote profiling")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1660,7 +1660,7 @@ def test_sample_target_module(self):
 | 
				
			||||||
class TestSampleProfilerErrorHandling(unittest.TestCase):
 | 
					class TestSampleProfilerErrorHandling(unittest.TestCase):
 | 
				
			||||||
    def test_invalid_pid(self):
 | 
					    def test_invalid_pid(self):
 | 
				
			||||||
        with self.assertRaises((OSError, RuntimeError)):
 | 
					        with self.assertRaises((OSError, RuntimeError)):
 | 
				
			||||||
            profile.sample.sample(-1, duration_sec=1)
 | 
					            profiling.sampling.sample.sample(-1, duration_sec=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_process_dies_during_sampling(self):
 | 
					    def test_process_dies_during_sampling(self):
 | 
				
			||||||
        with test_subprocess("import time; time.sleep(0.5); exit()") as proc:
 | 
					        with test_subprocess("import time; time.sleep(0.5); exit()") as proc:
 | 
				
			||||||
| 
						 | 
					@ -1669,7 +1669,7 @@ def test_process_dies_during_sampling(self):
 | 
				
			||||||
                mock.patch("sys.stdout", captured_output),
 | 
					                mock.patch("sys.stdout", captured_output),
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    profile.sample.sample(
 | 
					                    profiling.sampling.sample.sample(
 | 
				
			||||||
                        proc.pid,
 | 
					                        proc.pid,
 | 
				
			||||||
                        duration_sec=2,  # Longer than process lifetime
 | 
					                        duration_sec=2,  # Longer than process lifetime
 | 
				
			||||||
                        sample_interval_usec=50000,
 | 
					                        sample_interval_usec=50000,
 | 
				
			||||||
| 
						 | 
					@ -1685,7 +1685,7 @@ def test_process_dies_during_sampling(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_invalid_output_format(self):
 | 
					    def test_invalid_output_format(self):
 | 
				
			||||||
        with self.assertRaises(ValueError):
 | 
					        with self.assertRaises(ValueError):
 | 
				
			||||||
            profile.sample.sample(
 | 
					            profiling.sampling.sample.sample(
 | 
				
			||||||
                os.getpid(),
 | 
					                os.getpid(),
 | 
				
			||||||
                duration_sec=1,
 | 
					                duration_sec=1,
 | 
				
			||||||
                output_format="invalid_format",
 | 
					                output_format="invalid_format",
 | 
				
			||||||
| 
						 | 
					@ -1694,13 +1694,13 @@ def test_invalid_output_format(self):
 | 
				
			||||||
    def test_invalid_output_format_with_mocked_profiler(self):
 | 
					    def test_invalid_output_format_with_mocked_profiler(self):
 | 
				
			||||||
        """Test invalid output format with proper mocking to avoid permission issues."""
 | 
					        """Test invalid output format with proper mocking to avoid permission issues."""
 | 
				
			||||||
        with mock.patch(
 | 
					        with mock.patch(
 | 
				
			||||||
            "profile.sample.SampleProfiler"
 | 
					            "profiling.sampling.sample.SampleProfiler"
 | 
				
			||||||
        ) as mock_profiler_class:
 | 
					        ) as mock_profiler_class:
 | 
				
			||||||
            mock_profiler = mock.MagicMock()
 | 
					            mock_profiler = mock.MagicMock()
 | 
				
			||||||
            mock_profiler_class.return_value = mock_profiler
 | 
					            mock_profiler_class.return_value = mock_profiler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with self.assertRaises(ValueError) as cm:
 | 
					            with self.assertRaises(ValueError) as cm:
 | 
				
			||||||
                profile.sample.sample(
 | 
					                profiling.sampling.sample.sample(
 | 
				
			||||||
                    12345,
 | 
					                    12345,
 | 
				
			||||||
                    duration_sec=1,
 | 
					                    duration_sec=1,
 | 
				
			||||||
                    output_format="unknown_format",
 | 
					                    output_format="unknown_format",
 | 
				
			||||||
| 
						 | 
					@ -1787,23 +1787,23 @@ def _verify_coordinator_command(self, mock_popen, expected_target_args):
 | 
				
			||||||
        coordinator_cmd = args[0]
 | 
					        coordinator_cmd = args[0]
 | 
				
			||||||
        self.assertEqual(coordinator_cmd[0], sys.executable)
 | 
					        self.assertEqual(coordinator_cmd[0], sys.executable)
 | 
				
			||||||
        self.assertEqual(coordinator_cmd[1], "-m")
 | 
					        self.assertEqual(coordinator_cmd[1], "-m")
 | 
				
			||||||
        self.assertEqual(coordinator_cmd[2], "profile._sync_coordinator")
 | 
					        self.assertEqual(coordinator_cmd[2], "profiling.sampling._sync_coordinator")
 | 
				
			||||||
        self.assertEqual(coordinator_cmd[3], "12345")  # port
 | 
					        self.assertEqual(coordinator_cmd[3], "12345")  # port
 | 
				
			||||||
        # cwd is coordinator_cmd[4]
 | 
					        # cwd is coordinator_cmd[4]
 | 
				
			||||||
        self.assertEqual(coordinator_cmd[5:], expected_target_args)
 | 
					        self.assertEqual(coordinator_cmd[5:], expected_target_args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
					    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
				
			||||||
    def test_cli_module_argument_parsing(self):
 | 
					    def test_cli_module_argument_parsing(self):
 | 
				
			||||||
        test_args = ["profile.sample", "-m", "mymodule"]
 | 
					        test_args = ["profiling.sampling.sample", "-m", "mymodule"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("profile.sample.sample") as mock_sample,
 | 
					            mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
            mock.patch("subprocess.Popen") as mock_popen,
 | 
					            mock.patch("subprocess.Popen") as mock_popen,
 | 
				
			||||||
            mock.patch("socket.socket") as mock_socket,
 | 
					            mock.patch("socket.socket") as mock_socket,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
					            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self._verify_coordinator_command(mock_popen, ("-m", "mymodule"))
 | 
					            self._verify_coordinator_command(mock_popen, ("-m", "mymodule"))
 | 
				
			||||||
            mock_sample.assert_called_once_with(
 | 
					            mock_sample.assert_called_once_with(
 | 
				
			||||||
| 
						 | 
					@ -1821,16 +1821,16 @@ def test_cli_module_argument_parsing(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
					    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
				
			||||||
    def test_cli_module_with_arguments(self):
 | 
					    def test_cli_module_with_arguments(self):
 | 
				
			||||||
        test_args = ["profile.sample", "-m", "mymodule", "arg1", "arg2", "--flag"]
 | 
					        test_args = ["profiling.sampling.sample", "-m", "mymodule", "arg1", "arg2", "--flag"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("profile.sample.sample") as mock_sample,
 | 
					            mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
            mock.patch("subprocess.Popen") as mock_popen,
 | 
					            mock.patch("subprocess.Popen") as mock_popen,
 | 
				
			||||||
            mock.patch("socket.socket") as mock_socket,
 | 
					            mock.patch("socket.socket") as mock_socket,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
					            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self._verify_coordinator_command(mock_popen, ("-m", "mymodule", "arg1", "arg2", "--flag"))
 | 
					            self._verify_coordinator_command(mock_popen, ("-m", "mymodule", "arg1", "arg2", "--flag"))
 | 
				
			||||||
            mock_sample.assert_called_once_with(
 | 
					            mock_sample.assert_called_once_with(
 | 
				
			||||||
| 
						 | 
					@ -1848,16 +1848,16 @@ def test_cli_module_with_arguments(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
					    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
				
			||||||
    def test_cli_script_argument_parsing(self):
 | 
					    def test_cli_script_argument_parsing(self):
 | 
				
			||||||
        test_args = ["profile.sample", "myscript.py"]
 | 
					        test_args = ["profiling.sampling.sample", "myscript.py"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("profile.sample.sample") as mock_sample,
 | 
					            mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
            mock.patch("subprocess.Popen") as mock_popen,
 | 
					            mock.patch("subprocess.Popen") as mock_popen,
 | 
				
			||||||
            mock.patch("socket.socket") as mock_socket,
 | 
					            mock.patch("socket.socket") as mock_socket,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
					            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self._verify_coordinator_command(mock_popen, ("myscript.py",))
 | 
					            self._verify_coordinator_command(mock_popen, ("myscript.py",))
 | 
				
			||||||
            mock_sample.assert_called_once_with(
 | 
					            mock_sample.assert_called_once_with(
 | 
				
			||||||
| 
						 | 
					@ -1875,11 +1875,11 @@ def test_cli_script_argument_parsing(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
					    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
				
			||||||
    def test_cli_script_with_arguments(self):
 | 
					    def test_cli_script_with_arguments(self):
 | 
				
			||||||
        test_args = ["profile.sample", "myscript.py", "arg1", "arg2", "--flag"]
 | 
					        test_args = ["profiling.sampling.sample", "myscript.py", "arg1", "arg2", "--flag"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("profile.sample.sample") as mock_sample,
 | 
					            mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
            mock.patch("subprocess.Popen") as mock_popen,
 | 
					            mock.patch("subprocess.Popen") as mock_popen,
 | 
				
			||||||
            mock.patch("socket.socket") as mock_socket,
 | 
					            mock.patch("socket.socket") as mock_socket,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
| 
						 | 
					@ -1888,55 +1888,55 @@ def test_cli_script_with_arguments(self):
 | 
				
			||||||
            # Override specific behavior for this test
 | 
					            # Override specific behavior for this test
 | 
				
			||||||
            mock_process.wait.side_effect = [subprocess.TimeoutExpired(test_args, 0.1), None]
 | 
					            mock_process.wait.side_effect = [subprocess.TimeoutExpired(test_args, 0.1), None]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Verify the coordinator command was called
 | 
					            # Verify the coordinator command was called
 | 
				
			||||||
            args, kwargs = mock_popen.call_args
 | 
					            args, kwargs = mock_popen.call_args
 | 
				
			||||||
            coordinator_cmd = args[0]
 | 
					            coordinator_cmd = args[0]
 | 
				
			||||||
            self.assertEqual(coordinator_cmd[0], sys.executable)
 | 
					            self.assertEqual(coordinator_cmd[0], sys.executable)
 | 
				
			||||||
            self.assertEqual(coordinator_cmd[1], "-m")
 | 
					            self.assertEqual(coordinator_cmd[1], "-m")
 | 
				
			||||||
            self.assertEqual(coordinator_cmd[2], "profile._sync_coordinator")
 | 
					            self.assertEqual(coordinator_cmd[2], "profiling.sampling._sync_coordinator")
 | 
				
			||||||
            self.assertEqual(coordinator_cmd[3], "12345")  # port
 | 
					            self.assertEqual(coordinator_cmd[3], "12345")  # port
 | 
				
			||||||
            # cwd is coordinator_cmd[4]
 | 
					            # cwd is coordinator_cmd[4]
 | 
				
			||||||
            self.assertEqual(coordinator_cmd[5:], ("myscript.py", "arg1", "arg2", "--flag"))
 | 
					            self.assertEqual(coordinator_cmd[5:], ("myscript.py", "arg1", "arg2", "--flag"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_cli_mutually_exclusive_pid_module(self):
 | 
					    def test_cli_mutually_exclusive_pid_module(self):
 | 
				
			||||||
        test_args = ["profile.sample", "-p", "12345", "-m", "mymodule"]
 | 
					        test_args = ["profiling.sampling.sample", "-p", "12345", "-m", "mymodule"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("sys.stderr", io.StringIO()) as mock_stderr,
 | 
					            mock.patch("sys.stderr", io.StringIO()) as mock_stderr,
 | 
				
			||||||
            self.assertRaises(SystemExit) as cm,
 | 
					            self.assertRaises(SystemExit) as cm,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(cm.exception.code, 2)  # argparse error
 | 
					        self.assertEqual(cm.exception.code, 2)  # argparse error
 | 
				
			||||||
        error_msg = mock_stderr.getvalue()
 | 
					        error_msg = mock_stderr.getvalue()
 | 
				
			||||||
        self.assertIn("not allowed with argument", error_msg)
 | 
					        self.assertIn("not allowed with argument", error_msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_cli_mutually_exclusive_pid_script(self):
 | 
					    def test_cli_mutually_exclusive_pid_script(self):
 | 
				
			||||||
        test_args = ["profile.sample", "-p", "12345", "myscript.py"]
 | 
					        test_args = ["profiling.sampling.sample", "-p", "12345", "myscript.py"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("sys.stderr", io.StringIO()) as mock_stderr,
 | 
					            mock.patch("sys.stderr", io.StringIO()) as mock_stderr,
 | 
				
			||||||
            self.assertRaises(SystemExit) as cm,
 | 
					            self.assertRaises(SystemExit) as cm,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(cm.exception.code, 2)  # argparse error
 | 
					        self.assertEqual(cm.exception.code, 2)  # argparse error
 | 
				
			||||||
        error_msg = mock_stderr.getvalue()
 | 
					        error_msg = mock_stderr.getvalue()
 | 
				
			||||||
        self.assertIn("only one target type can be specified", error_msg)
 | 
					        self.assertIn("only one target type can be specified", error_msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_cli_no_target_specified(self):
 | 
					    def test_cli_no_target_specified(self):
 | 
				
			||||||
        test_args = ["profile.sample", "-d", "5"]
 | 
					        test_args = ["profiling.sampling.sample", "-d", "5"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("sys.stderr", io.StringIO()) as mock_stderr,
 | 
					            mock.patch("sys.stderr", io.StringIO()) as mock_stderr,
 | 
				
			||||||
            self.assertRaises(SystemExit) as cm,
 | 
					            self.assertRaises(SystemExit) as cm,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(cm.exception.code, 2)  # argparse error
 | 
					        self.assertEqual(cm.exception.code, 2)  # argparse error
 | 
				
			||||||
        error_msg = mock_stderr.getvalue()
 | 
					        error_msg = mock_stderr.getvalue()
 | 
				
			||||||
| 
						 | 
					@ -1945,18 +1945,18 @@ def test_cli_no_target_specified(self):
 | 
				
			||||||
    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
					    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
				
			||||||
    def test_cli_module_with_profiler_options(self):
 | 
					    def test_cli_module_with_profiler_options(self):
 | 
				
			||||||
        test_args = [
 | 
					        test_args = [
 | 
				
			||||||
            "profile.sample", "-i", "1000", "-d", "30", "-a",
 | 
					            "profiling.sampling.sample", "-i", "1000", "-d", "30", "-a",
 | 
				
			||||||
            "--sort-tottime", "-l", "20", "-m", "mymodule",
 | 
					            "--sort-tottime", "-l", "20", "-m", "mymodule",
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("profile.sample.sample") as mock_sample,
 | 
					            mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
            mock.patch("subprocess.Popen") as mock_popen,
 | 
					            mock.patch("subprocess.Popen") as mock_popen,
 | 
				
			||||||
            mock.patch("socket.socket") as mock_socket,
 | 
					            mock.patch("socket.socket") as mock_socket,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
					            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self._verify_coordinator_command(mock_popen, ("-m", "mymodule"))
 | 
					            self._verify_coordinator_command(mock_popen, ("-m", "mymodule"))
 | 
				
			||||||
            mock_sample.assert_called_once_with(
 | 
					            mock_sample.assert_called_once_with(
 | 
				
			||||||
| 
						 | 
					@ -1976,19 +1976,19 @@ def test_cli_module_with_profiler_options(self):
 | 
				
			||||||
    def test_cli_script_with_profiler_options(self):
 | 
					    def test_cli_script_with_profiler_options(self):
 | 
				
			||||||
        """Test script with various profiler options."""
 | 
					        """Test script with various profiler options."""
 | 
				
			||||||
        test_args = [
 | 
					        test_args = [
 | 
				
			||||||
            "profile.sample", "-i", "2000", "-d", "60",
 | 
					            "profiling.sampling.sample", "-i", "2000", "-d", "60",
 | 
				
			||||||
            "--collapsed", "-o", "output.txt",
 | 
					            "--collapsed", "-o", "output.txt",
 | 
				
			||||||
            "myscript.py", "scriptarg",
 | 
					            "myscript.py", "scriptarg",
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("profile.sample.sample") as mock_sample,
 | 
					            mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
            mock.patch("subprocess.Popen") as mock_popen,
 | 
					            mock.patch("subprocess.Popen") as mock_popen,
 | 
				
			||||||
            mock.patch("socket.socket") as mock_socket,
 | 
					            mock.patch("socket.socket") as mock_socket,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
					            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self._verify_coordinator_command(mock_popen, ("myscript.py", "scriptarg"))
 | 
					            self._verify_coordinator_command(mock_popen, ("myscript.py", "scriptarg"))
 | 
				
			||||||
            # Verify profiler options were passed correctly
 | 
					            # Verify profiler options were passed correctly
 | 
				
			||||||
| 
						 | 
					@ -2006,14 +2006,14 @@ def test_cli_script_with_profiler_options(self):
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_cli_empty_module_name(self):
 | 
					    def test_cli_empty_module_name(self):
 | 
				
			||||||
        test_args = ["profile.sample", "-m"]
 | 
					        test_args = ["profiling.sampling.sample", "-m"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("sys.stderr", io.StringIO()) as mock_stderr,
 | 
					            mock.patch("sys.stderr", io.StringIO()) as mock_stderr,
 | 
				
			||||||
            self.assertRaises(SystemExit) as cm,
 | 
					            self.assertRaises(SystemExit) as cm,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(cm.exception.code, 2)  # argparse error
 | 
					        self.assertEqual(cm.exception.code, 2)  # argparse error
 | 
				
			||||||
        error_msg = mock_stderr.getvalue()
 | 
					        error_msg = mock_stderr.getvalue()
 | 
				
			||||||
| 
						 | 
					@ -2021,29 +2021,29 @@ def test_cli_empty_module_name(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
					    @unittest.skipIf(is_emscripten, "socket.SO_REUSEADDR does not exist")
 | 
				
			||||||
    def test_cli_long_module_option(self):
 | 
					    def test_cli_long_module_option(self):
 | 
				
			||||||
        test_args = ["profile.sample", "--module", "mymodule", "arg1"]
 | 
					        test_args = ["profiling.sampling.sample", "--module", "mymodule", "arg1"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("profile.sample.sample") as mock_sample,
 | 
					            mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
            mock.patch("subprocess.Popen") as mock_popen,
 | 
					            mock.patch("subprocess.Popen") as mock_popen,
 | 
				
			||||||
            mock.patch("socket.socket") as mock_socket,
 | 
					            mock.patch("socket.socket") as mock_socket,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
					            self._setup_sync_mocks(mock_socket, mock_popen)
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self._verify_coordinator_command(mock_popen, ("-m", "mymodule", "arg1"))
 | 
					            self._verify_coordinator_command(mock_popen, ("-m", "mymodule", "arg1"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_cli_complex_script_arguments(self):
 | 
					    def test_cli_complex_script_arguments(self):
 | 
				
			||||||
        test_args = [
 | 
					        test_args = [
 | 
				
			||||||
            "profile.sample", "script.py",
 | 
					            "profiling.sampling.sample", "script.py",
 | 
				
			||||||
            "--input", "file.txt", "-v", "--output=/tmp/out", "positional"
 | 
					            "--input", "file.txt", "-v", "--output=/tmp/out", "positional"
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("profile.sample.sample") as mock_sample,
 | 
					            mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
            mock.patch("profile.sample._run_with_sync") as mock_run_with_sync,
 | 
					            mock.patch("profiling.sampling.sample._run_with_sync") as mock_run_with_sync,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            mock_process = mock.MagicMock()
 | 
					            mock_process = mock.MagicMock()
 | 
				
			||||||
            mock_process.pid = 12345
 | 
					            mock_process.pid = 12345
 | 
				
			||||||
| 
						 | 
					@ -2051,7 +2051,7 @@ def test_cli_complex_script_arguments(self):
 | 
				
			||||||
            mock_process.poll.return_value = None
 | 
					            mock_process.poll.return_value = None
 | 
				
			||||||
            mock_run_with_sync.return_value = mock_process
 | 
					            mock_run_with_sync.return_value = mock_process
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            mock_run_with_sync.assert_called_once_with((
 | 
					            mock_run_with_sync.assert_called_once_with((
 | 
				
			||||||
                sys.executable, "script.py",
 | 
					                sys.executable, "script.py",
 | 
				
			||||||
| 
						 | 
					@ -2063,16 +2063,16 @@ def test_cli_collapsed_format_validation(self):
 | 
				
			||||||
        test_cases = [
 | 
					        test_cases = [
 | 
				
			||||||
            # Test sort options are invalid with collapsed
 | 
					            # Test sort options are invalid with collapsed
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                ["profile.sample", "--collapsed", "--sort-nsamples", "-p", "12345"],
 | 
					                ["profiling.sampling.sample", "--collapsed", "--sort-nsamples", "-p", "12345"],
 | 
				
			||||||
                "sort",
 | 
					                "sort",
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                ["profile.sample", "--collapsed", "--sort-tottime", "-p", "12345"],
 | 
					                ["profiling.sampling.sample", "--collapsed", "--sort-tottime", "-p", "12345"],
 | 
				
			||||||
                "sort",
 | 
					                "sort",
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                [
 | 
					                [
 | 
				
			||||||
                    "profile.sample",
 | 
					                    "profiling.sampling.sample",
 | 
				
			||||||
                    "--collapsed",
 | 
					                    "--collapsed",
 | 
				
			||||||
                    "--sort-cumtime",
 | 
					                    "--sort-cumtime",
 | 
				
			||||||
                    "-p",
 | 
					                    "-p",
 | 
				
			||||||
| 
						 | 
					@ -2082,7 +2082,7 @@ def test_cli_collapsed_format_validation(self):
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                [
 | 
					                [
 | 
				
			||||||
                    "profile.sample",
 | 
					                    "profiling.sampling.sample",
 | 
				
			||||||
                    "--collapsed",
 | 
					                    "--collapsed",
 | 
				
			||||||
                    "--sort-sample-pct",
 | 
					                    "--sort-sample-pct",
 | 
				
			||||||
                    "-p",
 | 
					                    "-p",
 | 
				
			||||||
| 
						 | 
					@ -2092,7 +2092,7 @@ def test_cli_collapsed_format_validation(self):
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                [
 | 
					                [
 | 
				
			||||||
                    "profile.sample",
 | 
					                    "profiling.sampling.sample",
 | 
				
			||||||
                    "--collapsed",
 | 
					                    "--collapsed",
 | 
				
			||||||
                    "--sort-cumul-pct",
 | 
					                    "--sort-cumul-pct",
 | 
				
			||||||
                    "-p",
 | 
					                    "-p",
 | 
				
			||||||
| 
						 | 
					@ -2101,18 +2101,18 @@ def test_cli_collapsed_format_validation(self):
 | 
				
			||||||
                "sort",
 | 
					                "sort",
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                ["profile.sample", "--collapsed", "--sort-name", "-p", "12345"],
 | 
					                ["profiling.sampling.sample", "--collapsed", "--sort-name", "-p", "12345"],
 | 
				
			||||||
                "sort",
 | 
					                "sort",
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            # Test limit option is invalid with collapsed
 | 
					            # Test limit option is invalid with collapsed
 | 
				
			||||||
            (["profile.sample", "--collapsed", "-l", "20", "-p", "12345"], "limit"),
 | 
					            (["profiling.sampling.sample", "--collapsed", "-l", "20", "-p", "12345"], "limit"),
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                ["profile.sample", "--collapsed", "--limit", "20", "-p", "12345"],
 | 
					                ["profiling.sampling.sample", "--collapsed", "--limit", "20", "-p", "12345"],
 | 
				
			||||||
                "limit",
 | 
					                "limit",
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            # Test no-summary option is invalid with collapsed
 | 
					            # Test no-summary option is invalid with collapsed
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                ["profile.sample", "--collapsed", "--no-summary", "-p", "12345"],
 | 
					                ["profiling.sampling.sample", "--collapsed", "--no-summary", "-p", "12345"],
 | 
				
			||||||
                "summary",
 | 
					                "summary",
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
| 
						 | 
					@ -2123,7 +2123,7 @@ def test_cli_collapsed_format_validation(self):
 | 
				
			||||||
                mock.patch("sys.stderr", io.StringIO()) as mock_stderr,
 | 
					                mock.patch("sys.stderr", io.StringIO()) as mock_stderr,
 | 
				
			||||||
                self.assertRaises(SystemExit) as cm,
 | 
					                self.assertRaises(SystemExit) as cm,
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                profile.sample.main()
 | 
					                profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            self.assertEqual(cm.exception.code, 2)  # argparse error code
 | 
					            self.assertEqual(cm.exception.code, 2)  # argparse error code
 | 
				
			||||||
            error_msg = mock_stderr.getvalue()
 | 
					            error_msg = mock_stderr.getvalue()
 | 
				
			||||||
| 
						 | 
					@ -2132,13 +2132,13 @@ def test_cli_collapsed_format_validation(self):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_cli_default_collapsed_filename(self):
 | 
					    def test_cli_default_collapsed_filename(self):
 | 
				
			||||||
        """Test that collapsed format gets a default filename when not specified."""
 | 
					        """Test that collapsed format gets a default filename when not specified."""
 | 
				
			||||||
        test_args = ["profile.sample", "--collapsed", "-p", "12345"]
 | 
					        test_args = ["profiling.sampling.sample", "--collapsed", "-p", "12345"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("profile.sample.sample") as mock_sample,
 | 
					            mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            # Check that filename was set to default collapsed format
 | 
					            # Check that filename was set to default collapsed format
 | 
				
			||||||
            mock_sample.assert_called_once()
 | 
					            mock_sample.assert_called_once()
 | 
				
			||||||
| 
						 | 
					@ -2150,12 +2150,12 @@ def test_cli_custom_output_filenames(self):
 | 
				
			||||||
        """Test custom output filenames for both formats."""
 | 
					        """Test custom output filenames for both formats."""
 | 
				
			||||||
        test_cases = [
 | 
					        test_cases = [
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                ["profile.sample", "--pstats", "-o", "custom.pstats", "-p", "12345"],
 | 
					                ["profiling.sampling.sample", "--pstats", "-o", "custom.pstats", "-p", "12345"],
 | 
				
			||||||
                "custom.pstats",
 | 
					                "custom.pstats",
 | 
				
			||||||
                "pstats",
 | 
					                "pstats",
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            (
 | 
					            (
 | 
				
			||||||
                ["profile.sample", "--collapsed", "-o", "custom.txt", "-p", "12345"],
 | 
					                ["profiling.sampling.sample", "--collapsed", "-o", "custom.txt", "-p", "12345"],
 | 
				
			||||||
                "custom.txt",
 | 
					                "custom.txt",
 | 
				
			||||||
                "collapsed",
 | 
					                "collapsed",
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
| 
						 | 
					@ -2164,9 +2164,9 @@ def test_cli_custom_output_filenames(self):
 | 
				
			||||||
        for test_args, expected_filename, expected_format in test_cases:
 | 
					        for test_args, expected_filename, expected_format in test_cases:
 | 
				
			||||||
            with (
 | 
					            with (
 | 
				
			||||||
                mock.patch("sys.argv", test_args),
 | 
					                mock.patch("sys.argv", test_args),
 | 
				
			||||||
                mock.patch("profile.sample.sample") as mock_sample,
 | 
					                mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                profile.sample.main()
 | 
					                profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                mock_sample.assert_called_once()
 | 
					                mock_sample.assert_called_once()
 | 
				
			||||||
                call_args = mock_sample.call_args[1]
 | 
					                call_args = mock_sample.call_args[1]
 | 
				
			||||||
| 
						 | 
					@ -2176,32 +2176,32 @@ def test_cli_custom_output_filenames(self):
 | 
				
			||||||
    def test_cli_missing_required_arguments(self):
 | 
					    def test_cli_missing_required_arguments(self):
 | 
				
			||||||
        """Test that CLI requires PID argument."""
 | 
					        """Test that CLI requires PID argument."""
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", ["profile.sample"]),
 | 
					            mock.patch("sys.argv", ["profiling.sampling.sample"]),
 | 
				
			||||||
            mock.patch("sys.stderr", io.StringIO()),
 | 
					            mock.patch("sys.stderr", io.StringIO()),
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            with self.assertRaises(SystemExit):
 | 
					            with self.assertRaises(SystemExit):
 | 
				
			||||||
                profile.sample.main()
 | 
					                profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_cli_mutually_exclusive_format_options(self):
 | 
					    def test_cli_mutually_exclusive_format_options(self):
 | 
				
			||||||
        """Test that pstats and collapsed options are mutually exclusive."""
 | 
					        """Test that pstats and collapsed options are mutually exclusive."""
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch(
 | 
					            mock.patch(
 | 
				
			||||||
                "sys.argv",
 | 
					                "sys.argv",
 | 
				
			||||||
                ["profile.sample", "--pstats", "--collapsed", "-p", "12345"],
 | 
					                ["profiling.sampling.sample", "--pstats", "--collapsed", "-p", "12345"],
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            mock.patch("sys.stderr", io.StringIO()),
 | 
					            mock.patch("sys.stderr", io.StringIO()),
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            with self.assertRaises(SystemExit):
 | 
					            with self.assertRaises(SystemExit):
 | 
				
			||||||
                profile.sample.main()
 | 
					                profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_argument_parsing_basic(self):
 | 
					    def test_argument_parsing_basic(self):
 | 
				
			||||||
        test_args = ["profile.sample", "-p", "12345"]
 | 
					        test_args = ["profiling.sampling.sample", "-p", "12345"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with (
 | 
					        with (
 | 
				
			||||||
            mock.patch("sys.argv", test_args),
 | 
					            mock.patch("sys.argv", test_args),
 | 
				
			||||||
            mock.patch("profile.sample.sample") as mock_sample,
 | 
					            mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
        ):
 | 
					        ):
 | 
				
			||||||
            profile.sample.main()
 | 
					            profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            mock_sample.assert_called_once_with(
 | 
					            mock_sample.assert_called_once_with(
 | 
				
			||||||
                12345,
 | 
					                12345,
 | 
				
			||||||
| 
						 | 
					@ -2227,13 +2227,13 @@ def test_sort_options(self):
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for option, expected_sort_value in sort_options:
 | 
					        for option, expected_sort_value in sort_options:
 | 
				
			||||||
            test_args = ["profile.sample", option, "-p", "12345"]
 | 
					            test_args = ["profiling.sampling.sample", option, "-p", "12345"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            with (
 | 
					            with (
 | 
				
			||||||
                mock.patch("sys.argv", test_args),
 | 
					                mock.patch("sys.argv", test_args),
 | 
				
			||||||
                mock.patch("profile.sample.sample") as mock_sample,
 | 
					                mock.patch("profiling.sampling.sample.sample") as mock_sample,
 | 
				
			||||||
            ):
 | 
					            ):
 | 
				
			||||||
                profile.sample.main()
 | 
					                profiling.sampling.sample.main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                mock_sample.assert_called_once()
 | 
					                mock_sample.assert_called_once()
 | 
				
			||||||
                call_args = mock_sample.call_args[1]
 | 
					                call_args = mock_sample.call_args[1]
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@
 | 
				
			||||||
import unittest
 | 
					import unittest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# rip off all interesting stuff from test_profile
 | 
					# rip off all interesting stuff from test_profile
 | 
				
			||||||
import cProfile
 | 
					import profiling.tracing as cProfile
 | 
				
			||||||
import tempfile
 | 
					import tempfile
 | 
				
			||||||
import textwrap
 | 
					import textwrap
 | 
				
			||||||
from test.test_profile import ProfileTest, regenerate_expected_output
 | 
					from test.test_profile import ProfileTest, regenerate_expected_output
 | 
				
			||||||
| 
						 | 
					@ -2565,6 +2565,7 @@ LIBSUBDIRS=	asyncio \
 | 
				
			||||||
		multiprocessing multiprocessing/dummy \
 | 
							multiprocessing multiprocessing/dummy \
 | 
				
			||||||
		pathlib \
 | 
							pathlib \
 | 
				
			||||||
		profile \
 | 
							profile \
 | 
				
			||||||
 | 
							profiling profiling/sampling profiling/tracing \
 | 
				
			||||||
		pydoc_data \
 | 
							pydoc_data \
 | 
				
			||||||
		re \
 | 
							re \
 | 
				
			||||||
		site-packages \
 | 
							site-packages \
 | 
				
			||||||
| 
						 | 
					@ -2677,6 +2678,7 @@ TESTSUBDIRS=	idlelib/idle_test \
 | 
				
			||||||
		test/test_pathlib \
 | 
							test/test_pathlib \
 | 
				
			||||||
		test/test_pathlib/support \
 | 
							test/test_pathlib/support \
 | 
				
			||||||
		test/test_peg_generator \
 | 
							test/test_peg_generator \
 | 
				
			||||||
 | 
							test/test_profiling \
 | 
				
			||||||
		test/test_pydoc \
 | 
							test/test_pydoc \
 | 
				
			||||||
		test/test_pyrepl \
 | 
							test/test_pyrepl \
 | 
				
			||||||
		test/test_string \
 | 
							test/test_string \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,2 @@
 | 
				
			||||||
 | 
					Implement :pep:`799` -- A dedicated profiling package for organizing Python
 | 
				
			||||||
 | 
					profiling tools. Patch by Pablo Galindo.
 | 
				
			||||||
							
								
								
									
										1
									
								
								Python/stdlib_module_names.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Python/stdlib_module_names.h
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -215,6 +215,7 @@ static const char* _Py_stdlib_module_names[] = {
 | 
				
			||||||
"posixpath",
 | 
					"posixpath",
 | 
				
			||||||
"pprint",
 | 
					"pprint",
 | 
				
			||||||
"profile",
 | 
					"profile",
 | 
				
			||||||
 | 
					"profiling",
 | 
				
			||||||
"pstats",
 | 
					"pstats",
 | 
				
			||||||
"pty",
 | 
					"pty",
 | 
				
			||||||
"pwd",
 | 
					"pwd",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue