diff options
Diffstat (limited to 'Lib/pstats.py')
-rw-r--r-- | Lib/pstats.py | 111 |
1 files changed, 46 insertions, 65 deletions
diff --git a/Lib/pstats.py b/Lib/pstats.py index 566272dcae7..f5c592b81ba 100644 --- a/Lib/pstats.py +++ b/Lib/pstats.py @@ -37,6 +37,7 @@ import os import time import marshal import re +from functools import cmp_to_key __all__ = ["Stats"] @@ -70,20 +71,8 @@ class Stats: print_stats(5).print_callers(5) """ - def __init__(self, *args, **kwds): - # I can't figure out how to explicitly specify a stream keyword arg - # with *args: - # def __init__(self, *args, stream=sys.stdout): ... - # so I use **kwds and sqauwk if something unexpected is passed in. - self.stream = sys.stdout - if "stream" in kwds: - self.stream = kwds["stream"] - del kwds["stream"] - if kwds: - keys = kwds.keys() - keys.sort() - extras = ", ".join(["%s=%s" % (k, kwds[k]) for k in keys]) - raise ValueError("unrecognized keyword args: %s" % extras) + def __init__(self, *args, stream=None): + self.stream = stream or sys.stdout if not len(args): arg = None else: @@ -100,22 +89,21 @@ class Stats: self.total_calls = 0 self.prim_calls = 0 self.max_name_len = 0 - self.top_level = {} + self.top_level = set() self.stats = {} self.sort_arg_dict = {} self.load_stats(arg) - trouble = 1 try: self.get_top_level_stats() - trouble = 0 - finally: - if trouble: - print("Invalid timing data", end=' ', file=self.stream) - if self.files: print(self.files[-1], end=' ', file=self.stream) - print(file=self.stream) + except Exception: + print("Invalid timing data %s" % + (self.files[-1] if self.files else ''), file=self.stream) + raise def load_stats(self, arg): - if not arg: self.stats = {} + if arg is None: + self.stats = {} + return elif isinstance(arg, str): f = open(arg, 'rb') self.stats = marshal.load(f) @@ -125,13 +113,13 @@ class Stats: arg = time.ctime(file_stats.st_mtime) + " " + arg except: # in case this is not unix pass - self.files = [ arg ] + self.files = [arg] elif hasattr(arg, 'create_stats'): arg.create_stats() self.stats = arg.stats arg.stats = {} if not self.stats: - raise TypeError("Cannot create or construct a %r object from '%r''" + raise TypeError("Cannot create or construct a %r object from %r" % (self.__class__, arg)) return @@ -141,34 +129,34 @@ class Stats: self.prim_calls += cc self.total_tt += tt if ("jprofile", 0, "profiler") in callers: - self.top_level[func] = None + self.top_level.add(func) if len(func_std_string(func)) > self.max_name_len: self.max_name_len = len(func_std_string(func)) def add(self, *arg_list): - if not arg_list: return self - if len(arg_list) > 1: self.add(*arg_list[1:]) - other = arg_list[0] - if type(self) != type(other): - other = Stats(other) - self.files += other.files - self.total_calls += other.total_calls - self.prim_calls += other.prim_calls - self.total_tt += other.total_tt - for func in other.top_level: - self.top_level[func] = None - - if self.max_name_len < other.max_name_len: - self.max_name_len = other.max_name_len - - self.fcn_list = None - - for func, stat in other.stats.items(): - if func in self.stats: - old_func_stat = self.stats[func] - else: - old_func_stat = (0, 0, 0, 0, {},) - self.stats[func] = add_func_stats(old_func_stat, stat) + if not arg_list: + return self + for item in reversed(arg_list): + if type(self) != type(item): + item = Stats(item) + self.files += item.files + self.total_calls += item.total_calls + self.prim_calls += item.prim_calls + self.total_tt += item.total_tt + for func in item.top_level: + self.top_level.add(func) + + if self.max_name_len < item.max_name_len: + self.max_name_len = item.max_name_len + + self.fcn_list = None + + for func, stat in item.stats.items(): + if func in self.stats: + old_func_stat = self.stats[func] + else: + old_func_stat = (0, 0, 0, 0, {},) + self.stats[func] = add_func_stats(old_func_stat, stat) return self def dump_stats(self, filename): @@ -238,7 +226,7 @@ class Stats: stats_list.append((cc, nc, tt, ct) + func + (func_std_string(func), func)) - stats_list.sort(key=CmpToKey(TupleComp(sort_tuple).compare)) + stats_list.sort(key=cmp_to_key(TupleComp(sort_tuple).compare)) self.fcn_list = fcn_list = [] for tuple in stats_list: @@ -269,9 +257,9 @@ class Stats: else: newstats[newfunc] = (cc, nc, tt, ct, newcallers) old_top = self.top_level - self.top_level = new_top = {} + self.top_level = new_top = set() for func in old_top: - new_top[func_strip_path(func)] = None + new_top.add(func_strip_path(func)) self.max_name_len = max_name_len @@ -280,7 +268,8 @@ class Stats: return self def calc_callees(self): - if self.all_callees: return + if self.all_callees: + return self.all_callees = all_callees = {} for func, (cc, nc, tt, ct, callers) in self.stats.items(): if not func in all_callees: @@ -350,7 +339,8 @@ class Stats: def print_stats(self, *amount): for filename in self.files: print(filename, file=self.stream) - if self.files: print(file=self.stream) + if self.files: + print(file=self.stream) indent = ' ' * 8 for func in self.top_level: print(indent, func_get_function_name(func), file=self.stream) @@ -436,7 +426,7 @@ class Stats: print(' ncalls tottime percall cumtime percall', end=' ', file=self.stream) print('filename:lineno(function)', file=self.stream) - def print_line(self, func): # hack : should print percentages + def print_line(self, func): # hack: should print percentages cc, nc, tt, ct, callers = self.stats[func] c = str(nc) if nc != cc: @@ -475,15 +465,6 @@ class TupleComp: return direction return 0 -def CmpToKey(mycmp): - 'Convert a cmp= function into a key= function' - class K(object): - def __init__(self, obj): - self.obj = obj - def __lt__(self, other): - return mycmp(self.obj, other.obj) == -1 - return K - #************************************************************************** # func_name is a triple (file:string, line:int, name:string) @@ -670,7 +651,7 @@ if __name__ == '__main__': print("No statistics object is loaded.", file=self.stream) return abbrevs = self.stats.get_sort_arg_defs() - if line and not filter(lambda x,a=abbrevs: x not in a,line.split()): + if line and all((x in abbrevs) for x in line.split()): self.stats.sort_stats(*line.split()) else: print("Valid sort keys (unique prefixes are accepted):", file=self.stream) |