3 # Quick script to process the *summary* output from SCons.Debug.caller()
4 # and print indented calling trees with call counts.
6 # The way to use this is to add something like the following to a function
7 # for which you want information about who calls it and how many times:
9 # from SCons.Debug import caller
10 # caller(0, 1, 2, 3, 4, 5)
12 # Each integer represents how many stack frames back SCons will go
13 # and capture the calling information, so in the above example it will
14 # capture the calls six levels up the stack in a central dictionary.
16 # At the end of any run where SCons.Debug.caller() is used, SCons will
17 # print a summary of the calls and counts that looks like the following:
19 # Callers of Node/__init__.py:629(calc_signature):
20 # 1 Node/__init__.py:683(calc_signature)
21 # Callers of Node/__init__.py:676(gen_binfo):
22 # 6 Node/FS.py:2035(current)
23 # 1 Node/__init__.py:722(get_bsig)
25 # If you cut-and-paste that summary output and feed it to this script
26 # on standard input, it will figure out how these entries hook up and
27 # print a calling tree for each one looking something like:
29 # Node/__init__.py:676(gen_binfo)
30 # Node/FS.py:2035(current) 6
31 # Taskmaster.py:253(make_ready_current) 18
32 # Script/Main.py:201(make_ready) 18
34 # Note that you should *not* look at the call-count numbers in the right
35 # hand column as the actual number of times each line *was called by*
36 # the function on the next line. Rather, it's the *total* number
37 # of times each function was found in the call chain for any of the
38 # calls to SCons.Debug.caller(). If you're looking at more than one
39 # function at the same time, for example, their counts will intermix.
40 # So use this to get a *general* idea of who's calling what, not for
41 # fine-grained performance tuning.
45 def __init__(self
, file_line_func
):
46 self
.file_line_func
= file_line_func
56 e
= AllCalls
[flf
] = Entry(flf
)
59 prefix
= 'Callers of '
62 for line
in sys
.stdin
.readlines():
65 elif line
[:len(prefix
)] == prefix
:
66 c
= get_call(line
[len(prefix
):-2])
68 num_calls
, flf
= line
.strip().split()
70 c
.called_by
.append((e
, num_calls
))
75 def print_entry(e
, level
, calls
):
76 print('%-72s%6s' % ((' '*2*level
) + e
.file_line_func
, calls
))
78 print((' '*2*(level
+1))+'RECURSION')
83 print_entry(c
[0], level
+1, c
[1])
88 for e
in [ e
for e
in list(AllCalls
.values()) if not e
.calls
]:
93 # indent-tabs-mode:nil
95 # vim: set expandtab tabstop=4 shiftwidth=4: