As letmaik pointed out, there is an open bug ticket for this capability. However, the submitter (alexnvdias) already did the work for this and posted their code in the original bug ticket and in the github pull request. If you want to be able to use it, you can just subclass pstats.Stats
and implement what they already submitted. It works for me just fine.
import pstats
class Stats(pstats.Stats):
# list the tuple indices and directions for sorting,
# along with some printable description
sort_arg_dict_default = {
"calls" : (((1,-1), ), "call count"),
"ncalls" : (((1,-1), ), "call count"),
"cumtime" : (((4,-1), ), "cumulative time"),
"cumulative" : (((4,-1), ), "cumulative time"),
"file" : (((6, 1), ), "file name"),
"filename" : (((6, 1), ), "file name"),
"line" : (((7, 1), ), "line number"),
"module" : (((6, 1), ), "file name"),
"name" : (((8, 1), ), "function name"),
"nfl" : (((8, 1),(6, 1),(7, 1),), "name/file/line"),
"pcalls" : (((0,-1), ), "primitive call count"),
"stdname" : (((9, 1), ), "standard name"),
"time" : (((2,-1), ), "internal time"),
"tottime" : (((2,-1), ), "internal time"),
"cumulativepercall": (((5,-1), ), "cumulative time per call"),
"totalpercall" : (((3,-1), ), "total time per call"),
}
def sort_stats(self, *field):
if not field:
self.fcn_list = 0
return self
if len(field) == 1 and isinstance(field[0], int):
# Be compatible with old profiler
field = [ {-1: "stdname",
0: "calls",
1: "time",
2: "cumulative"}[field[0]] ]
elif len(field) >= 2:
for arg in field[1:]:
if type(arg) != type(field[0]):
raise TypeError("Can't have mixed argument type")
sort_arg_defs = self.get_sort_arg_defs()
sort_tuple = ()
self.sort_type = ""
connector = ""
for word in field:
if isinstance(word, pstats.SortKey):
word = word.value
sort_tuple = sort_tuple + sort_arg_defs[word][0]
self.sort_type += connector + sort_arg_defs[word][1]
connector = ", "
stats_list = []
for func, (cc, nc, tt, ct, callers) in self.stats.items():
if nc == 0:
npc = 0
else:
npc = float(tt)/nc
if cc == 0:
cpc = 0
else:
cpc = float(ct)/cc
stats_list.append((cc, nc, tt, npc, ct, cpc) + func +
(pstats.func_std_string(func), func))
stats_list.sort(key=pstats.cmp_to_key(pstats.TupleComp(sort_tuple).compare))
self.fcn_list = fcn_list = []
for tuple in stats_list:
fcn_list.append(tuple[-1])
return self
s = Stats('test.dat')
s.sort_stats('totalpercall')
s.print_stats()
Result:
Mon Apr 29 12:50:37 2024 test.dat
2003 function calls in 0.058 seconds
Ordered by: total time per call
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.001 0.001 0.058 0.058 test.py:2(<module>)
1000 0.029 0.000 0.029 0.000 test.py:2(add)
1000 0.028 0.000 0.028 0.000 test.py:8(sub)
1 0.000 0.000 0.058 0.058 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}