Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/ExeBy/smexe_ro.../usr/lib64/python3....
File: pstats.py
"""Class for printing reports on profiled python code."""
[0] Fix | Delete
[1] Fix | Delete
# Written by James Roskind
[2] Fix | Delete
# Based on prior profile module by Sjoerd Mullender...
[3] Fix | Delete
# which was hacked somewhat by: Guido van Rossum
[4] Fix | Delete
[5] Fix | Delete
# Copyright Disney Enterprises, Inc. All Rights Reserved.
[6] Fix | Delete
# Licensed to PSF under a Contributor Agreement
[7] Fix | Delete
#
[8] Fix | Delete
# Licensed under the Apache License, Version 2.0 (the "License");
[9] Fix | Delete
# you may not use this file except in compliance with the License.
[10] Fix | Delete
# You may obtain a copy of the License at
[11] Fix | Delete
#
[12] Fix | Delete
# http://www.apache.org/licenses/LICENSE-2.0
[13] Fix | Delete
#
[14] Fix | Delete
# Unless required by applicable law or agreed to in writing, software
[15] Fix | Delete
# distributed under the License is distributed on an "AS IS" BASIS,
[16] Fix | Delete
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
[17] Fix | Delete
# either express or implied. See the License for the specific language
[18] Fix | Delete
# governing permissions and limitations under the License.
[19] Fix | Delete
[20] Fix | Delete
[21] Fix | Delete
import sys
[22] Fix | Delete
import os
[23] Fix | Delete
import time
[24] Fix | Delete
import marshal
[25] Fix | Delete
import re
[26] Fix | Delete
from functools import cmp_to_key
[27] Fix | Delete
[28] Fix | Delete
__all__ = ["Stats"]
[29] Fix | Delete
[30] Fix | Delete
class Stats:
[31] Fix | Delete
"""This class is used for creating reports from data generated by the
[32] Fix | Delete
Profile class. It is a "friend" of that class, and imports data either
[33] Fix | Delete
by direct access to members of Profile class, or by reading in a dictionary
[34] Fix | Delete
that was emitted (via marshal) from the Profile class.
[35] Fix | Delete
[36] Fix | Delete
The big change from the previous Profiler (in terms of raw functionality)
[37] Fix | Delete
is that an "add()" method has been provided to combine Stats from
[38] Fix | Delete
several distinct profile runs. Both the constructor and the add()
[39] Fix | Delete
method now take arbitrarily many file names as arguments.
[40] Fix | Delete
[41] Fix | Delete
All the print methods now take an argument that indicates how many lines
[42] Fix | Delete
to print. If the arg is a floating point number between 0 and 1.0, then
[43] Fix | Delete
it is taken as a decimal percentage of the available lines to be printed
[44] Fix | Delete
(e.g., .1 means print 10% of all available lines). If it is an integer,
[45] Fix | Delete
it is taken to mean the number of lines of data that you wish to have
[46] Fix | Delete
printed.
[47] Fix | Delete
[48] Fix | Delete
The sort_stats() method now processes some additional options (i.e., in
[49] Fix | Delete
addition to the old -1, 0, 1, or 2 that are respectively interpreted as
[50] Fix | Delete
'stdname', 'calls', 'time', and 'cumulative'). It takes an arbitrary number
[51] Fix | Delete
of quoted strings to select the sort order.
[52] Fix | Delete
[53] Fix | Delete
For example sort_stats('time', 'name') sorts on the major key of 'internal
[54] Fix | Delete
function time', and on the minor key of 'the name of the function'. Look at
[55] Fix | Delete
the two tables in sort_stats() and get_sort_arg_defs(self) for more
[56] Fix | Delete
examples.
[57] Fix | Delete
[58] Fix | Delete
All methods return self, so you can string together commands like:
[59] Fix | Delete
Stats('foo', 'goo').strip_dirs().sort_stats('calls').\
[60] Fix | Delete
print_stats(5).print_callers(5)
[61] Fix | Delete
"""
[62] Fix | Delete
[63] Fix | Delete
def __init__(self, *args, stream=None):
[64] Fix | Delete
self.stream = stream or sys.stdout
[65] Fix | Delete
if not len(args):
[66] Fix | Delete
arg = None
[67] Fix | Delete
else:
[68] Fix | Delete
arg = args[0]
[69] Fix | Delete
args = args[1:]
[70] Fix | Delete
self.init(arg)
[71] Fix | Delete
self.add(*args)
[72] Fix | Delete
[73] Fix | Delete
def init(self, arg):
[74] Fix | Delete
self.all_callees = None # calc only if needed
[75] Fix | Delete
self.files = []
[76] Fix | Delete
self.fcn_list = None
[77] Fix | Delete
self.total_tt = 0
[78] Fix | Delete
self.total_calls = 0
[79] Fix | Delete
self.prim_calls = 0
[80] Fix | Delete
self.max_name_len = 0
[81] Fix | Delete
self.top_level = set()
[82] Fix | Delete
self.stats = {}
[83] Fix | Delete
self.sort_arg_dict = {}
[84] Fix | Delete
self.load_stats(arg)
[85] Fix | Delete
try:
[86] Fix | Delete
self.get_top_level_stats()
[87] Fix | Delete
except Exception:
[88] Fix | Delete
print("Invalid timing data %s" %
[89] Fix | Delete
(self.files[-1] if self.files else ''), file=self.stream)
[90] Fix | Delete
raise
[91] Fix | Delete
[92] Fix | Delete
def load_stats(self, arg):
[93] Fix | Delete
if arg is None:
[94] Fix | Delete
self.stats = {}
[95] Fix | Delete
return
[96] Fix | Delete
elif isinstance(arg, str):
[97] Fix | Delete
with open(arg, 'rb') as f:
[98] Fix | Delete
self.stats = marshal.load(f)
[99] Fix | Delete
try:
[100] Fix | Delete
file_stats = os.stat(arg)
[101] Fix | Delete
arg = time.ctime(file_stats.st_mtime) + " " + arg
[102] Fix | Delete
except: # in case this is not unix
[103] Fix | Delete
pass
[104] Fix | Delete
self.files = [arg]
[105] Fix | Delete
elif hasattr(arg, 'create_stats'):
[106] Fix | Delete
arg.create_stats()
[107] Fix | Delete
self.stats = arg.stats
[108] Fix | Delete
arg.stats = {}
[109] Fix | Delete
if not self.stats:
[110] Fix | Delete
raise TypeError("Cannot create or construct a %r object from %r"
[111] Fix | Delete
% (self.__class__, arg))
[112] Fix | Delete
return
[113] Fix | Delete
[114] Fix | Delete
def get_top_level_stats(self):
[115] Fix | Delete
for func, (cc, nc, tt, ct, callers) in self.stats.items():
[116] Fix | Delete
self.total_calls += nc
[117] Fix | Delete
self.prim_calls += cc
[118] Fix | Delete
self.total_tt += tt
[119] Fix | Delete
if ("jprofile", 0, "profiler") in callers:
[120] Fix | Delete
self.top_level.add(func)
[121] Fix | Delete
if len(func_std_string(func)) > self.max_name_len:
[122] Fix | Delete
self.max_name_len = len(func_std_string(func))
[123] Fix | Delete
[124] Fix | Delete
def add(self, *arg_list):
[125] Fix | Delete
if not arg_list:
[126] Fix | Delete
return self
[127] Fix | Delete
for item in reversed(arg_list):
[128] Fix | Delete
if type(self) != type(item):
[129] Fix | Delete
item = Stats(item)
[130] Fix | Delete
self.files += item.files
[131] Fix | Delete
self.total_calls += item.total_calls
[132] Fix | Delete
self.prim_calls += item.prim_calls
[133] Fix | Delete
self.total_tt += item.total_tt
[134] Fix | Delete
for func in item.top_level:
[135] Fix | Delete
self.top_level.add(func)
[136] Fix | Delete
[137] Fix | Delete
if self.max_name_len < item.max_name_len:
[138] Fix | Delete
self.max_name_len = item.max_name_len
[139] Fix | Delete
[140] Fix | Delete
self.fcn_list = None
[141] Fix | Delete
[142] Fix | Delete
for func, stat in item.stats.items():
[143] Fix | Delete
if func in self.stats:
[144] Fix | Delete
old_func_stat = self.stats[func]
[145] Fix | Delete
else:
[146] Fix | Delete
old_func_stat = (0, 0, 0, 0, {},)
[147] Fix | Delete
self.stats[func] = add_func_stats(old_func_stat, stat)
[148] Fix | Delete
return self
[149] Fix | Delete
[150] Fix | Delete
def dump_stats(self, filename):
[151] Fix | Delete
"""Write the profile data to a file we know how to load back."""
[152] Fix | Delete
with open(filename, 'wb') as f:
[153] Fix | Delete
marshal.dump(self.stats, f)
[154] Fix | Delete
[155] Fix | Delete
# list the tuple indices and directions for sorting,
[156] Fix | Delete
# along with some printable description
[157] Fix | Delete
sort_arg_dict_default = {
[158] Fix | Delete
"calls" : (((1,-1), ), "call count"),
[159] Fix | Delete
"ncalls" : (((1,-1), ), "call count"),
[160] Fix | Delete
"cumtime" : (((3,-1), ), "cumulative time"),
[161] Fix | Delete
"cumulative": (((3,-1), ), "cumulative time"),
[162] Fix | Delete
"file" : (((4, 1), ), "file name"),
[163] Fix | Delete
"filename" : (((4, 1), ), "file name"),
[164] Fix | Delete
"line" : (((5, 1), ), "line number"),
[165] Fix | Delete
"module" : (((4, 1), ), "file name"),
[166] Fix | Delete
"name" : (((6, 1), ), "function name"),
[167] Fix | Delete
"nfl" : (((6, 1),(4, 1),(5, 1),), "name/file/line"),
[168] Fix | Delete
"pcalls" : (((0,-1), ), "primitive call count"),
[169] Fix | Delete
"stdname" : (((7, 1), ), "standard name"),
[170] Fix | Delete
"time" : (((2,-1), ), "internal time"),
[171] Fix | Delete
"tottime" : (((2,-1), ), "internal time"),
[172] Fix | Delete
}
[173] Fix | Delete
[174] Fix | Delete
def get_sort_arg_defs(self):
[175] Fix | Delete
"""Expand all abbreviations that are unique."""
[176] Fix | Delete
if not self.sort_arg_dict:
[177] Fix | Delete
self.sort_arg_dict = dict = {}
[178] Fix | Delete
bad_list = {}
[179] Fix | Delete
for word, tup in self.sort_arg_dict_default.items():
[180] Fix | Delete
fragment = word
[181] Fix | Delete
while fragment:
[182] Fix | Delete
if not fragment:
[183] Fix | Delete
break
[184] Fix | Delete
if fragment in dict:
[185] Fix | Delete
bad_list[fragment] = 0
[186] Fix | Delete
break
[187] Fix | Delete
dict[fragment] = tup
[188] Fix | Delete
fragment = fragment[:-1]
[189] Fix | Delete
for word in bad_list:
[190] Fix | Delete
del dict[word]
[191] Fix | Delete
return self.sort_arg_dict
[192] Fix | Delete
[193] Fix | Delete
def sort_stats(self, *field):
[194] Fix | Delete
if not field:
[195] Fix | Delete
self.fcn_list = 0
[196] Fix | Delete
return self
[197] Fix | Delete
if len(field) == 1 and isinstance(field[0], int):
[198] Fix | Delete
# Be compatible with old profiler
[199] Fix | Delete
field = [ {-1: "stdname",
[200] Fix | Delete
0: "calls",
[201] Fix | Delete
1: "time",
[202] Fix | Delete
2: "cumulative"}[field[0]] ]
[203] Fix | Delete
[204] Fix | Delete
sort_arg_defs = self.get_sort_arg_defs()
[205] Fix | Delete
sort_tuple = ()
[206] Fix | Delete
self.sort_type = ""
[207] Fix | Delete
connector = ""
[208] Fix | Delete
for word in field:
[209] Fix | Delete
sort_tuple = sort_tuple + sort_arg_defs[word][0]
[210] Fix | Delete
self.sort_type += connector + sort_arg_defs[word][1]
[211] Fix | Delete
connector = ", "
[212] Fix | Delete
[213] Fix | Delete
stats_list = []
[214] Fix | Delete
for func, (cc, nc, tt, ct, callers) in self.stats.items():
[215] Fix | Delete
stats_list.append((cc, nc, tt, ct) + func +
[216] Fix | Delete
(func_std_string(func), func))
[217] Fix | Delete
[218] Fix | Delete
stats_list.sort(key=cmp_to_key(TupleComp(sort_tuple).compare))
[219] Fix | Delete
[220] Fix | Delete
self.fcn_list = fcn_list = []
[221] Fix | Delete
for tuple in stats_list:
[222] Fix | Delete
fcn_list.append(tuple[-1])
[223] Fix | Delete
return self
[224] Fix | Delete
[225] Fix | Delete
def reverse_order(self):
[226] Fix | Delete
if self.fcn_list:
[227] Fix | Delete
self.fcn_list.reverse()
[228] Fix | Delete
return self
[229] Fix | Delete
[230] Fix | Delete
def strip_dirs(self):
[231] Fix | Delete
oldstats = self.stats
[232] Fix | Delete
self.stats = newstats = {}
[233] Fix | Delete
max_name_len = 0
[234] Fix | Delete
for func, (cc, nc, tt, ct, callers) in oldstats.items():
[235] Fix | Delete
newfunc = func_strip_path(func)
[236] Fix | Delete
if len(func_std_string(newfunc)) > max_name_len:
[237] Fix | Delete
max_name_len = len(func_std_string(newfunc))
[238] Fix | Delete
newcallers = {}
[239] Fix | Delete
for func2, caller in callers.items():
[240] Fix | Delete
newcallers[func_strip_path(func2)] = caller
[241] Fix | Delete
[242] Fix | Delete
if newfunc in newstats:
[243] Fix | Delete
newstats[newfunc] = add_func_stats(
[244] Fix | Delete
newstats[newfunc],
[245] Fix | Delete
(cc, nc, tt, ct, newcallers))
[246] Fix | Delete
else:
[247] Fix | Delete
newstats[newfunc] = (cc, nc, tt, ct, newcallers)
[248] Fix | Delete
old_top = self.top_level
[249] Fix | Delete
self.top_level = new_top = set()
[250] Fix | Delete
for func in old_top:
[251] Fix | Delete
new_top.add(func_strip_path(func))
[252] Fix | Delete
[253] Fix | Delete
self.max_name_len = max_name_len
[254] Fix | Delete
[255] Fix | Delete
self.fcn_list = None
[256] Fix | Delete
self.all_callees = None
[257] Fix | Delete
return self
[258] Fix | Delete
[259] Fix | Delete
def calc_callees(self):
[260] Fix | Delete
if self.all_callees:
[261] Fix | Delete
return
[262] Fix | Delete
self.all_callees = all_callees = {}
[263] Fix | Delete
for func, (cc, nc, tt, ct, callers) in self.stats.items():
[264] Fix | Delete
if not func in all_callees:
[265] Fix | Delete
all_callees[func] = {}
[266] Fix | Delete
for func2, caller in callers.items():
[267] Fix | Delete
if not func2 in all_callees:
[268] Fix | Delete
all_callees[func2] = {}
[269] Fix | Delete
all_callees[func2][func] = caller
[270] Fix | Delete
return
[271] Fix | Delete
[272] Fix | Delete
#******************************************************************
[273] Fix | Delete
# The following functions support actual printing of reports
[274] Fix | Delete
#******************************************************************
[275] Fix | Delete
[276] Fix | Delete
# Optional "amount" is either a line count, or a percentage of lines.
[277] Fix | Delete
[278] Fix | Delete
def eval_print_amount(self, sel, list, msg):
[279] Fix | Delete
new_list = list
[280] Fix | Delete
if isinstance(sel, str):
[281] Fix | Delete
try:
[282] Fix | Delete
rex = re.compile(sel)
[283] Fix | Delete
except re.error:
[284] Fix | Delete
msg += " <Invalid regular expression %r>\n" % sel
[285] Fix | Delete
return new_list, msg
[286] Fix | Delete
new_list = []
[287] Fix | Delete
for func in list:
[288] Fix | Delete
if rex.search(func_std_string(func)):
[289] Fix | Delete
new_list.append(func)
[290] Fix | Delete
else:
[291] Fix | Delete
count = len(list)
[292] Fix | Delete
if isinstance(sel, float) and 0.0 <= sel < 1.0:
[293] Fix | Delete
count = int(count * sel + .5)
[294] Fix | Delete
new_list = list[:count]
[295] Fix | Delete
elif isinstance(sel, int) and 0 <= sel < count:
[296] Fix | Delete
count = sel
[297] Fix | Delete
new_list = list[:count]
[298] Fix | Delete
if len(list) != len(new_list):
[299] Fix | Delete
msg += " List reduced from %r to %r due to restriction <%r>\n" % (
[300] Fix | Delete
len(list), len(new_list), sel)
[301] Fix | Delete
[302] Fix | Delete
return new_list, msg
[303] Fix | Delete
[304] Fix | Delete
def get_print_list(self, sel_list):
[305] Fix | Delete
width = self.max_name_len
[306] Fix | Delete
if self.fcn_list:
[307] Fix | Delete
stat_list = self.fcn_list[:]
[308] Fix | Delete
msg = " Ordered by: " + self.sort_type + '\n'
[309] Fix | Delete
else:
[310] Fix | Delete
stat_list = list(self.stats.keys())
[311] Fix | Delete
msg = " Random listing order was used\n"
[312] Fix | Delete
[313] Fix | Delete
for selection in sel_list:
[314] Fix | Delete
stat_list, msg = self.eval_print_amount(selection, stat_list, msg)
[315] Fix | Delete
[316] Fix | Delete
count = len(stat_list)
[317] Fix | Delete
[318] Fix | Delete
if not stat_list:
[319] Fix | Delete
return 0, stat_list
[320] Fix | Delete
print(msg, file=self.stream)
[321] Fix | Delete
if count < len(self.stats):
[322] Fix | Delete
width = 0
[323] Fix | Delete
for func in stat_list:
[324] Fix | Delete
if len(func_std_string(func)) > width:
[325] Fix | Delete
width = len(func_std_string(func))
[326] Fix | Delete
return width+2, stat_list
[327] Fix | Delete
[328] Fix | Delete
def print_stats(self, *amount):
[329] Fix | Delete
for filename in self.files:
[330] Fix | Delete
print(filename, file=self.stream)
[331] Fix | Delete
if self.files:
[332] Fix | Delete
print(file=self.stream)
[333] Fix | Delete
indent = ' ' * 8
[334] Fix | Delete
for func in self.top_level:
[335] Fix | Delete
print(indent, func_get_function_name(func), file=self.stream)
[336] Fix | Delete
[337] Fix | Delete
print(indent, self.total_calls, "function calls", end=' ', file=self.stream)
[338] Fix | Delete
if self.total_calls != self.prim_calls:
[339] Fix | Delete
print("(%d primitive calls)" % self.prim_calls, end=' ', file=self.stream)
[340] Fix | Delete
print("in %.3f seconds" % self.total_tt, file=self.stream)
[341] Fix | Delete
print(file=self.stream)
[342] Fix | Delete
width, list = self.get_print_list(amount)
[343] Fix | Delete
if list:
[344] Fix | Delete
self.print_title()
[345] Fix | Delete
for func in list:
[346] Fix | Delete
self.print_line(func)
[347] Fix | Delete
print(file=self.stream)
[348] Fix | Delete
print(file=self.stream)
[349] Fix | Delete
return self
[350] Fix | Delete
[351] Fix | Delete
def print_callees(self, *amount):
[352] Fix | Delete
width, list = self.get_print_list(amount)
[353] Fix | Delete
if list:
[354] Fix | Delete
self.calc_callees()
[355] Fix | Delete
[356] Fix | Delete
self.print_call_heading(width, "called...")
[357] Fix | Delete
for func in list:
[358] Fix | Delete
if func in self.all_callees:
[359] Fix | Delete
self.print_call_line(width, func, self.all_callees[func])
[360] Fix | Delete
else:
[361] Fix | Delete
self.print_call_line(width, func, {})
[362] Fix | Delete
print(file=self.stream)
[363] Fix | Delete
print(file=self.stream)
[364] Fix | Delete
return self
[365] Fix | Delete
[366] Fix | Delete
def print_callers(self, *amount):
[367] Fix | Delete
width, list = self.get_print_list(amount)
[368] Fix | Delete
if list:
[369] Fix | Delete
self.print_call_heading(width, "was called by...")
[370] Fix | Delete
for func in list:
[371] Fix | Delete
cc, nc, tt, ct, callers = self.stats[func]
[372] Fix | Delete
self.print_call_line(width, func, callers, "<-")
[373] Fix | Delete
print(file=self.stream)
[374] Fix | Delete
print(file=self.stream)
[375] Fix | Delete
return self
[376] Fix | Delete
[377] Fix | Delete
def print_call_heading(self, name_size, column_title):
[378] Fix | Delete
print("Function ".ljust(name_size) + column_title, file=self.stream)
[379] Fix | Delete
# print sub-header only if we have new-style callers
[380] Fix | Delete
subheader = False
[381] Fix | Delete
for cc, nc, tt, ct, callers in self.stats.values():
[382] Fix | Delete
if callers:
[383] Fix | Delete
value = next(iter(callers.values()))
[384] Fix | Delete
subheader = isinstance(value, tuple)
[385] Fix | Delete
break
[386] Fix | Delete
if subheader:
[387] Fix | Delete
print(" "*name_size + " ncalls tottime cumtime", file=self.stream)
[388] Fix | Delete
[389] Fix | Delete
def print_call_line(self, name_size, source, call_dict, arrow="->"):
[390] Fix | Delete
print(func_std_string(source).ljust(name_size) + arrow, end=' ', file=self.stream)
[391] Fix | Delete
if not call_dict:
[392] Fix | Delete
print(file=self.stream)
[393] Fix | Delete
return
[394] Fix | Delete
clist = sorted(call_dict.keys())
[395] Fix | Delete
indent = ""
[396] Fix | Delete
for func in clist:
[397] Fix | Delete
name = func_std_string(func)
[398] Fix | Delete
value = call_dict[func]
[399] Fix | Delete
if isinstance(value, tuple):
[400] Fix | Delete
nc, cc, tt, ct = value
[401] Fix | Delete
if nc != cc:
[402] Fix | Delete
substats = '%d/%d' % (nc, cc)
[403] Fix | Delete
else:
[404] Fix | Delete
substats = '%d' % (nc,)
[405] Fix | Delete
substats = '%s %s %s %s' % (substats.rjust(7+2*len(indent)),
[406] Fix | Delete
f8(tt), f8(ct), name)
[407] Fix | Delete
left_width = name_size + 1
[408] Fix | Delete
else:
[409] Fix | Delete
substats = '%s(%r) %s' % (name, value, f8(self.stats[func][3]))
[410] Fix | Delete
left_width = name_size + 3
[411] Fix | Delete
print(indent*left_width + substats, file=self.stream)
[412] Fix | Delete
indent = " "
[413] Fix | Delete
[414] Fix | Delete
def print_title(self):
[415] Fix | Delete
print(' ncalls tottime percall cumtime percall', end=' ', file=self.stream)
[416] Fix | Delete
print('filename:lineno(function)', file=self.stream)
[417] Fix | Delete
[418] Fix | Delete
def print_line(self, func): # hack: should print percentages
[419] Fix | Delete
cc, nc, tt, ct, callers = self.stats[func]
[420] Fix | Delete
c = str(nc)
[421] Fix | Delete
if nc != cc:
[422] Fix | Delete
c = c + '/' + str(cc)
[423] Fix | Delete
print(c.rjust(9), end=' ', file=self.stream)
[424] Fix | Delete
print(f8(tt), end=' ', file=self.stream)
[425] Fix | Delete
if nc == 0:
[426] Fix | Delete
print(' '*8, end=' ', file=self.stream)
[427] Fix | Delete
else:
[428] Fix | Delete
print(f8(tt/nc), end=' ', file=self.stream)
[429] Fix | Delete
print(f8(ct), end=' ', file=self.stream)
[430] Fix | Delete
if cc == 0:
[431] Fix | Delete
print(' '*8, end=' ', file=self.stream)
[432] Fix | Delete
else:
[433] Fix | Delete
print(f8(ct/cc), end=' ', file=self.stream)
[434] Fix | Delete
print(func_std_string(func), file=self.stream)
[435] Fix | Delete
[436] Fix | Delete
class TupleComp:
[437] Fix | Delete
"""This class provides a generic function for comparing any two tuples.
[438] Fix | Delete
Each instance records a list of tuple-indices (from most significant
[439] Fix | Delete
to least significant), and sort direction (ascending or decending) for
[440] Fix | Delete
each tuple-index. The compare functions can then be used as the function
[441] Fix | Delete
argument to the system sort() function when a list of tuples need to be
[442] Fix | Delete
sorted in the instances order."""
[443] Fix | Delete
[444] Fix | Delete
def __init__(self, comp_select_list):
[445] Fix | Delete
self.comp_select_list = comp_select_list
[446] Fix | Delete
[447] Fix | Delete
def compare (self, left, right):
[448] Fix | Delete
for index, direction in self.comp_select_list:
[449] Fix | Delete
l = left[index]
[450] Fix | Delete
r = right[index]
[451] Fix | Delete
if l < r:
[452] Fix | Delete
return -direction
[453] Fix | Delete
if l > r:
[454] Fix | Delete
return direction
[455] Fix | Delete
return 0
[456] Fix | Delete
[457] Fix | Delete
[458] Fix | Delete
#**************************************************************************
[459] Fix | Delete
# func_name is a triple (file:string, line:int, name:string)
[460] Fix | Delete
[461] Fix | Delete
def func_strip_path(func_name):
[462] Fix | Delete
filename, line, name = func_name
[463] Fix | Delete
return os.path.basename(filename), line, name
[464] Fix | Delete
[465] Fix | Delete
def func_get_function_name(func):
[466] Fix | Delete
return func[2]
[467] Fix | Delete
[468] Fix | Delete
def func_std_string(func_name): # match what old profile produced
[469] Fix | Delete
if func_name[:2] == ('~', 0):
[470] Fix | Delete
# special case for built-in functions
[471] Fix | Delete
name = func_name[2]
[472] Fix | Delete
if name.startswith('<') and name.endswith('>'):
[473] Fix | Delete
return '{%s}' % name[1:-1]
[474] Fix | Delete
else:
[475] Fix | Delete
return name
[476] Fix | Delete
else:
[477] Fix | Delete
return "%s:%d(%s)" % func_name
[478] Fix | Delete
[479] Fix | Delete
#**************************************************************************
[480] Fix | Delete
# The following functions combine statists for pairs functions.
[481] Fix | Delete
# The bulk of the processing involves correctly handling "call" lists,
[482] Fix | Delete
# such as callers and callees.
[483] Fix | Delete
#**************************************************************************
[484] Fix | Delete
[485] Fix | Delete
def add_func_stats(target, source):
[486] Fix | Delete
"""Add together all the stats for two profile entries."""
[487] Fix | Delete
cc, nc, tt, ct, callers = source
[488] Fix | Delete
t_cc, t_nc, t_tt, t_ct, t_callers = target
[489] Fix | Delete
return (cc+t_cc, nc+t_nc, tt+t_tt, ct+t_ct,
[490] Fix | Delete
add_callers(t_callers, callers))
[491] Fix | Delete
[492] Fix | Delete
def add_callers(target, source):
[493] Fix | Delete
"""Combine two caller lists in a single list."""
[494] Fix | Delete
new_callers = {}
[495] Fix | Delete
for func, caller in target.items():
[496] Fix | Delete
new_callers[func] = caller
[497] Fix | Delete
for func, caller in source.items():
[498] Fix | Delete
if func in new_callers:
[499] Fix | Delete
12
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function