Skip to main content

Lib/pstats.py

cpython 3.14 @ ab2d84fe1023/Lib/pstats.py

pstats is the analysis front-end for Python's profiling infrastructure. It consumes the binary stats files written by cProfile.dump_stats (or the equivalent from the older profile module) and presents them as sorted, filtered, human-readable tables. The module is also the right place to merge results from multiple independent profiling runs via the add method.

The central class is Stats. Its constructor accepts a filename, an open file object, or an already-populated Profile instance. Internally all stats are stored in a flat dict keyed by (filename, lineno, funcname) tuples. Each value is a six-element tuple carrying primitive call count, total call count, inline time, cumulative time, and a sub-dict of callers.

Sorting is done by a small set of named keys. The constants are defined in the SortKey enum introduced in 3.7, but the older string aliases such as "cumulative" and "time" are still accepted. Filtering with print_stats takes either an integer row limit or a regex pattern applied against the formatted function name.

Map

LinesSymbolRolegopy
1-40module header, SortKey enumPublic sort-key constants
41-110Stats.__init__ / load_statsDeserialise one or more profile sources
111-160Stats.addMerge a second Stats into this one
161-220Stats.sort_statsOrder the internal dict by one or more keys
221-290Stats.print_statsFiltered columnar output to a stream
291-370Stats.print_callers / print_calleesPer-function caller and callee tables
371-430Stats.strip_dirsRemove directory prefix from filenames
431-510Formatting helpers (f8, func_std_string, etc.)Low-level number and name formatting
511-590Stats.dump_stats / reverse_order / miscSerialisation and utility methods

Reading

SortKey enum and sort-key aliases (lines 1 to 40)

cpython 3.14 @ ab2d84fe1023/Lib/pstats.py#L1-40

The SortKey enum gives each sort criterion a stable programmatic name. The older string aliases are kept in a separate mapping so that both SortKey.CUMULATIVE and the plain string "cumulative" resolve to the same internal tuple index.

class SortKey(str, enum.Enum):
CALLS = 'calls', 'ncalls'
CUMULATIVE = 'cumulative', 'cumtime'
FILENAME = 'filename', 'module'
LINE = 'line'
NAME = 'name'
NFL = 'nfl'
PCALLS = 'pcalls'
STDNAME = 'stdname'
TIME = 'time', 'tottime'

Stats.__init__ and load_stats (lines 41 to 110)

cpython 3.14 @ ab2d84fe1023/Lib/pstats.py#L41-110

The constructor iterates over its positional arguments. Each argument can be a filename string, a Profile object, or another Stats instance. Filenames are unpickled; live Profile objects have create_stats() called on them first. The stream keyword argument controls where text output is written (default sys.stdout).

def __init__(self, *args, stream=None):
self.stream = stream or sys.stdout
if not len(args):
arg = None
else:
arg = args[0]
args = args[1:]
self.init(arg)
self.add(*args)

Stats.add for merging runs (lines 111 to 160)

cpython 3.14 @ ab2d84fe1023/Lib/pstats.py#L111-160

add accepts the same argument types as the constructor. It walks the incoming stats dict and, for each key already present in self.stats, adds element-wise: primitive calls, total calls, inline time, and cumulative time. Callers sub-dicts are merged with the same logic. This makes it straightforward to combine profiles from parallel worker processes.

def add(self, *arg_list):
for item in arg_list:
if type(item) == type(self):
item_stats = item.stats
else:
item_stats = Stats(item).stats
for func, (cc, nc, tt, ct, callers) in item_stats.items():
if func in self.stats:
... # element-wise add
else:
self.stats[func] = cc, nc, tt, ct, callers.copy()
return self

sort_stats and sort key resolution (lines 161 to 220)

cpython 3.14 @ ab2d84fe1023/Lib/pstats.py#L161-220

sort_stats accepts one or more keys, validates them against the alias table, and stores the resulting sort tuple. The actual sort happens lazily the first time output is requested. Passing -1 restores the original insertion order, which is useful when you want to call print_stats with no particular ordering.

def sort_stats(self, *field):
if not field:
self.fcn_list = 0
return self
...
self.fcn_list = fcn_list = []
for func in sorted(self.stats.keys(), key=...):
fcn_list.append(func)
return self

cpython 3.14 @ ab2d84fe1023/Lib/pstats.py#L221-370

print_stats accepts an integer row limit and zero or more regex restrictions. Each restriction is applied as a re.search against the formatted function name string, so multiple patterns narrow the output step by step. print_callers and print_callees reuse the same filtering logic but pivot the display to show the call graph edges adjacent to each matching function.

def print_stats(self, *amount):
for filename in self.files:
print(filename, file=self.stream)
...
for func in fcn_list:
if self.fcn_list:
...
cc, nc, tt, ct, callers = self.stats[func]
...

gopy mirror

Not yet ported.